From b285803c4e8c37302f6e02624a6127667d628305 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Tue, 25 Jun 2019 19:49:54 -0400
Subject: Youtube Api Exploration

---
 src/client/apis/youtube/YoutubeBox.tsx | 72 ++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 src/client/apis/youtube/YoutubeBox.tsx

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
new file mode 100644
index 000000000..ee190750f
--- /dev/null
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -0,0 +1,72 @@
+import "../../views/nodes/WebBox.scss";
+import React = require("react");
+import { FieldViewProps, FieldView } from "../../views/nodes/FieldView";
+import { HtmlField } from "../../../new_fields/HtmlField";
+import { WebField } from "../../../new_fields/URLField";
+import { observer } from "mobx-react";
+import { computed, reaction, IReactionDisposer } from 'mobx';
+import { DocumentDecorations } from "../../views/DocumentDecorations";
+import { InkingControl } from "../../views/InkingControl";
+import * as YoutubeApi from "./youtubeApiSample";
+import { Utils } from "../../../Utils";
+import { DocServer } from "../../DocServer";
+
+
+@observer
+export class YoutubeBox extends React.Component<FieldViewProps> {
+
+    private youtubeApiKey: string = "";
+
+    public static LayoutString() { return FieldView.LayoutString(YoutubeBox); }
+
+    async componentWillMount() {
+        let apiKey = await DocServer.getYoutubeApiKey();
+        this.youtubeApiKey = apiKey;
+        YoutubeApi.authorizedGetChannel(this.youtubeApiKey);
+    }
+
+    _ignore = 0;
+    onPreWheel = (e: React.WheelEvent) => {
+        this._ignore = e.timeStamp;
+    }
+    onPrePointer = (e: React.PointerEvent) => {
+        this._ignore = e.timeStamp;
+    }
+    onPostPointer = (e: React.PointerEvent) => {
+        if (this._ignore !== e.timeStamp) {
+            e.stopPropagation();
+        }
+    }
+    onPostWheel = (e: React.WheelEvent) => {
+        if (this._ignore !== e.timeStamp) {
+            e.stopPropagation();
+        }
+    }
+    render() {
+        let field = this.props.Document[this.props.fieldKey];
+        let view;
+        YoutubeApi.readFsFile();
+        if (field instanceof HtmlField) {
+            view = <span id="webBox-htmlSpan" dangerouslySetInnerHTML={{ __html: field.html }} />;
+        } else if (field instanceof WebField) {
+            view = <iframe src={field.url.href} style={{ position: "absolute", width: "100%", height: "100%" }} />;
+        } else {
+            view = <iframe src={"https://crossorigin.me/https://cs.brown.edu"} style={{ position: "absolute", width: "100%", height: "100%" }} />;
+        }
+        let content =
+            <div style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
+                {view}
+            </div>;
+
+        let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
+
+        let classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
+        return (
+            <>
+                <div className={classname}  >
+                    {content}
+                </div>
+                {!frozen ? (null) : <div className="webBox-overlay" onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer} />}
+            </>);
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From b86050edd2da3acca258f117e8350aa8d53272d9 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Wed, 26 Jun 2019 15:14:46 -0400
Subject: Sample working onserver side

---
 client_secret.json                            |   1 +
 client_secret.json.json                       |   1 -
 src/client/DocServer.ts                       |   6 +-
 src/client/apis/youtube/YoutubeBox.tsx        |   9 +-
 src/client/apis/youtube/youtubeApiSample.d.ts |   3 -
 src/client/apis/youtube/youtubeApiSample.js   | 122 -----------------------
 src/server/Message.ts                         |   6 +-
 src/server/Search.ts                          |   2 +-
 src/server/index.ts                           |  29 +++---
 src/server/youtubeApi/youtubeApiSample.d.ts   |   2 +
 src/server/youtubeApi/youtubeApiSample.js     | 135 ++++++++++++++++++++++++++
 11 files changed, 162 insertions(+), 154 deletions(-)
 create mode 100644 client_secret.json
 delete mode 100644 client_secret.json.json
 delete mode 100644 src/client/apis/youtube/youtubeApiSample.d.ts
 delete mode 100644 src/client/apis/youtube/youtubeApiSample.js
 create mode 100644 src/server/youtubeApi/youtubeApiSample.d.ts
 create mode 100644 src/server/youtubeApi/youtubeApiSample.js

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/client_secret.json b/client_secret.json
new file mode 100644
index 000000000..a9c698421
--- /dev/null
+++ b/client_secret.json
@@ -0,0 +1 @@
+{"installed":{"client_id":"1005546247619-kqpnvh42mpa803tem8556b87umi4j9r0.apps.googleusercontent.com","project_id":"brown-dash","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"WshLb5TH9SdFVGGbQcnYj7IU","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}
\ No newline at end of file
diff --git a/client_secret.json.json b/client_secret.json.json
deleted file mode 100644
index 99dfbdf7b..000000000
--- a/client_secret.json.json
+++ /dev/null
@@ -1 +0,0 @@
-{"installed":{"client_id":"605555062960-ebbjrsv6ugkigpdoh6cdb3g6gmhdalnn.apps.googleusercontent.com","project_id":"dulcet-name-244817","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"3e8A9w5OJacQCGYIrHTu9ef2","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}
\ No newline at end of file
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index c9cbce78e..9dae54d74 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -1,5 +1,5 @@
 import * as OpenSocket from 'socket.io-client';
-import { MessageStore } from "./../server/Message";
+import { MessageStore, YoutubeQueryTypes } from "./../server/Message";
 import { Opt } from '../new_fields/Doc';
 import { Utils, emptyFunction } from '../Utils';
 import { SerializationHelper } from './util/SerializationHelper';
@@ -47,8 +47,8 @@ export namespace DocServer {
         }
     }
 
-    export async function getYoutubeApiKey() {
-        let apiKey = await Utils.EmitCallback(_socket, MessageStore.YoutubeApiKey, undefined);
+    export async function getYoutubeChannels() {
+        let apiKey = await Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, YoutubeQueryTypes.Channels);
         return apiKey;
     }
 
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index ee190750f..b029c51ec 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -7,7 +7,6 @@ import { observer } from "mobx-react";
 import { computed, reaction, IReactionDisposer } from 'mobx';
 import { DocumentDecorations } from "../../views/DocumentDecorations";
 import { InkingControl } from "../../views/InkingControl";
-import * as YoutubeApi from "./youtubeApiSample";
 import { Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 
@@ -15,14 +14,11 @@ import { DocServer } from "../../DocServer";
 @observer
 export class YoutubeBox extends React.Component<FieldViewProps> {
 
-    private youtubeApiKey: string = "";
 
     public static LayoutString() { return FieldView.LayoutString(YoutubeBox); }
 
-    async componentWillMount() {
-        let apiKey = await DocServer.getYoutubeApiKey();
-        this.youtubeApiKey = apiKey;
-        YoutubeApi.authorizedGetChannel(this.youtubeApiKey);
+    componentWillMount() {
+        DocServer.getYoutubeChannels();
     }
 
     _ignore = 0;
@@ -45,7 +41,6 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     render() {
         let field = this.props.Document[this.props.fieldKey];
         let view;
-        YoutubeApi.readFsFile();
         if (field instanceof HtmlField) {
             view = <span id="webBox-htmlSpan" dangerouslySetInnerHTML={{ __html: field.html }} />;
         } else if (field instanceof WebField) {
diff --git a/src/client/apis/youtube/youtubeApiSample.d.ts b/src/client/apis/youtube/youtubeApiSample.d.ts
deleted file mode 100644
index 87a669e36..000000000
--- a/src/client/apis/youtube/youtubeApiSample.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-
-declare const YoutubeApi: any;
-export = YoutubeApi;
\ No newline at end of file
diff --git a/src/client/apis/youtube/youtubeApiSample.js b/src/client/apis/youtube/youtubeApiSample.js
deleted file mode 100644
index 7f14f2d3e..000000000
--- a/src/client/apis/youtube/youtubeApiSample.js
+++ /dev/null
@@ -1,122 +0,0 @@
-import { Utils } from "tslint";
-
-
-// If modifying these scopes, delete your previously saved credentials
-// at ~/.credentials/youtube-nodejs-quickstart.json
-let SCOPES = ['https://www.googleapis.com/auth/youtube.readonly'];
-let TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
-    process.env.USERPROFILE) + '/.credentials/';
-let TOKEN_PATH = TOKEN_DIR + 'youtube-nodejs-quickstart.json';
-
-
-
-function authorizedGetChannel(apiKey) {
-    // Authorize a client with the loaded credentials, then call the YouTube API.
-    authorize(JSON.parse(apiKey), getChannel);
-}
-
-
-/**
- * Create an OAuth2 client with the given credentials, and then execute the
- * given callback function.
- *
- * @param {Object} credentials The authorization client credentials.
- * @param {function} callback The callback to call with the authorized client.
- */
-function authorize(credentials, callback) {
-    let clientSecret = credentials.installed.client_secret;
-    let clientId = credentials.installed.client_id;
-    let redirectUrl = credentials.installed.redirect_uris[0];
-    let oauth2Client = new OAuth2(clientId, clientSecret, redirectUrl);
-
-    // Check if we have previously stored a token.
-    fs.readFile(TOKEN_PATH, function (err, token) {
-        if (err) {
-            getNewToken(oauth2Client, callback);
-        } else {
-            oauth2Client.credentials = JSON.parse(token);
-            callback(oauth2Client);
-        }
-    });
-}
-
-/**
- * Get and store new token after prompting for user authorization, and then
- * execute the given callback with the authorized OAuth2 client.
- *
- * @param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
- * @param {getEventsCallback} callback The callback to call with the authorized
- *     client.
- */
-function getNewToken(oauth2Client, callback) {
-    var authUrl = oauth2Client.generateAuthUrl({
-        access_type: 'offline',
-        scope: SCOPES
-    });
-    console.log('Authorize this app by visiting this url: ', authUrl);
-    var rl = readline.createInterface({
-        input: process.stdin,
-        output: process.stdout
-    });
-    rl.question('Enter the code from that page here: ', function (code) {
-        rl.close();
-        oauth2Client.getToken(code, function (err, token) {
-            if (err) {
-                console.log('Error while trying to retrieve access token', err);
-                return;
-            }
-            oauth2Client.credentials = token;
-            storeToken(token);
-            callback(oauth2Client);
-        });
-    });
-}
-
-/**
- * Store token to disk be used in later program executions.
- *
- * @param {Object} token The token to store to disk.
- */
-function storeToken(token) {
-    try {
-        fs.mkdirSync(TOKEN_DIR);
-    } catch (err) {
-        if (err.code != 'EEXIST') {
-            throw err;
-        }
-    }
-    fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
-        if (err) throw err;
-        console.log('Token stored to ' + TOKEN_PATH);
-    });
-    console.log('Token stored to ' + TOKEN_PATH);
-}
-
-/**
- * Lists the names and IDs of up to 10 files.
- *
- * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
- */
-function getChannel(auth) {
-    var service = google.youtube('v3');
-    service.channels.list({
-        auth: auth,
-        part: 'snippet,contentDetails,statistics',
-        forUsername: 'GoogleDevelopers'
-    }, function (err, response) {
-        if (err) {
-            console.log('The API returned an error: ' + err);
-            return;
-        }
-        var channels = response.data.items;
-        if (channels.length == 0) {
-            console.log('No channel found.');
-        } else {
-            console.log('This channel\'s ID is %s. Its title is \'%s\', and ' +
-                'it has %s views.',
-                channels[0].id,
-                channels[0].snippet.title,
-                channels[0].statistics.viewCount);
-        }
-    });
-}
\ No newline at end of file
diff --git a/src/server/Message.ts b/src/server/Message.ts
index ee9142222..0fc5dd4b5 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -24,6 +24,10 @@ export interface Transferable {
     readonly data?: any;
 }
 
+export enum YoutubeQueryTypes {
+    Channels
+}
+
 export interface Reference {
     readonly id: string;
 }
@@ -45,5 +49,5 @@ export namespace MessageStore {
     export const GetRefFields = new Message<string[]>("Get Ref Fields");
     export const UpdateField = new Message<Diff>("Update Ref Field");
     export const CreateField = new Message<Reference>("Create Ref Field");
-    export const YoutubeApiKey = new Message<string>("Youtube Api Key");
+    export const YoutubeApiQuery = new Message<YoutubeQueryTypes>("Youtube Api Query");
 }
diff --git a/src/server/Search.ts b/src/server/Search.ts
index 5ca5578a7..d776480c6 100644
--- a/src/server/Search.ts
+++ b/src/server/Search.ts
@@ -14,7 +14,7 @@ export class Search {
             });
             return res;
         } catch (e) {
-            console.warn("Search error: " + e + document);
+            // console.warn("Search error: " + e + document);
         }
     }
 
diff --git a/src/server/index.ts b/src/server/index.ts
index 2629519a7..b36cb0bf2 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -24,7 +24,7 @@ import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLo
 import { DashUserModel } from './authentication/models/user_model';
 import { Client } from './Client';
 import { Database } from './database';
-import { MessageStore, Transferable, Types, Diff } from "./Message";
+import { MessageStore, Transferable, Types, Diff, YoutubeQueryTypes as YoutubeQueryType } from "./Message";
 import { RouteStore } from './RouteStore';
 const app = express();
 const config = require('../../webpack.config');
@@ -37,15 +37,16 @@ import c = require("crypto");
 import { Search } from './Search';
 import { debug } from 'util';
 import _ = require('lodash');
+import * as YoutubeApi from './youtubeApi/youtubeApiSample.js';
 const MongoStore = require('connect-mongo')(session);
 const mongoose = require('mongoose');
-//let fs = require('fs');
-let readline = require('readline');
-let { google } = require('googleapis');
-let OAuth2 = google.auth.OAuth2;
+// let { google } = require('googleapis');
+// let OAuth2 = google.auth.OAuth2;
 
 
 const download = (url: string, dest: fs.PathLike) => request.get(url).pipe(fs.createWriteStream(dest));
+let youtubeApiKey: string;
+YoutubeApi.readApiKey((apiKey: string) => youtubeApiKey = apiKey);
 
 const mongoUrl = 'mongodb://localhost:27017/Dash';
 mongoose.connect(mongoUrl);
@@ -315,7 +316,7 @@ server.on("connection", function (socket: Socket) {
     Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields);
 
     Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField);
-    Utils.AddServerHandlerCallback(socket, MessageStore.YoutubeApiKey, GetYoutubeApiKey);
+    Utils.AddServerHandlerCallback(socket, MessageStore.YoutubeApiQuery, HandleYoutubeQuery);
     Utils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff));
     Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField);
     Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields);
@@ -366,18 +367,14 @@ function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => v
     Database.Instance.getDocuments(ids, callback, "newDocuments");
 }
 
-function GetYoutubeApiKey(callback: (result?: string) => void) {
-    // Load client secrets from a local file.
-    fs.readFile('client_secret.json', function processClientSecrets(err: any, content: any) {
-        if (err) {
-            console.log('Error loading client secret file: ' + err);
-            return;
-        }
-        callback(content);
-    });
+function HandleYoutubeQuery([type, callback]: [YoutubeQueryType, (result?: string) => void]) {
+    switch (type) {
+        case YoutubeQueryType.Channels:
+            YoutubeApi.authorizedGetChannel(youtubeApiKey);
+            break;
+    }
 }
 
-
 const suffixMap: { [type: string]: (string | [string, string | ((json: any) => any)]) } = {
     "number": "_n",
     "string": "_t",
diff --git a/src/server/youtubeApi/youtubeApiSample.d.ts b/src/server/youtubeApi/youtubeApiSample.d.ts
new file mode 100644
index 000000000..427f54608
--- /dev/null
+++ b/src/server/youtubeApi/youtubeApiSample.d.ts
@@ -0,0 +1,2 @@
+declare const YoutubeApi: any;
+export = YoutubeApi;
\ No newline at end of file
diff --git a/src/server/youtubeApi/youtubeApiSample.js b/src/server/youtubeApi/youtubeApiSample.js
new file mode 100644
index 000000000..7d5c936f5
--- /dev/null
+++ b/src/server/youtubeApi/youtubeApiSample.js
@@ -0,0 +1,135 @@
+const fs = require('fs');
+const readline = require('readline');
+const { google } = require('googleapis');
+const OAuth2 = google.auth.OAuth2;
+
+
+// If modifying these scopes, delete your previously saved credentials
+// at ~/.credentials/youtube-nodejs-quickstart.json
+let SCOPES = ['https://www.googleapis.com/auth/youtube.readonly'];
+let TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
+    process.env.USERPROFILE) + '/.credentials/';
+let TOKEN_PATH = TOKEN_DIR + 'youtube-nodejs-quickstart.json';
+
+module.exports.readApiKey = (callback) => {
+    fs.readFile('client_secret.json', function processClientSecrets(err, content) {
+        if (err) {
+            console.log('Error loading client secret file: ' + err);
+            return;
+        }
+        callback(content);
+    });
+}
+
+module.exports.authorizedGetChannel = (apiKey) => {
+    //this didnt get called
+    console.log("I get called");
+    // Authorize a client with the loaded credentials, then call the YouTube API.
+    authorize(JSON.parse(apiKey), getChannel);
+}
+
+
+/**
+ * Create an OAuth2 client with the given credentials, and then execute the
+ * given callback function.
+ *
+ * @param {Object} credentials The authorization client credentials.
+ * @param {function} callback The callback to call with the authorized client.
+ */
+function authorize(credentials, callback) {
+    let clientSecret = credentials.installed.client_secret;
+    let clientId = credentials.installed.client_id;
+    let redirectUrl = credentials.installed.redirect_uris[0];
+    let oauth2Client = new OAuth2(clientId, clientSecret, redirectUrl);
+
+    // Check if we have previously stored a token.
+    fs.readFile(TOKEN_PATH, function (err, token) {
+        if (err) {
+            getNewToken(oauth2Client, callback);
+        } else {
+            oauth2Client.credentials = JSON.parse(token);
+            callback(oauth2Client);
+        }
+    });
+}
+
+/**
+ * Get and store new token after prompting for user authorization, and then
+ * execute the given callback with the authorized OAuth2 client.
+ *
+ * @param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
+ * @param {getEventsCallback} callback The callback to call with the authorized
+ *     client.
+ */
+function getNewToken(oauth2Client, callback) {
+    var authUrl = oauth2Client.generateAuthUrl({
+        access_type: 'offline',
+        scope: SCOPES
+    });
+    console.log('Authorize this app by visiting this url: ', authUrl);
+    var rl = readline.createInterface({
+        input: process.stdin,
+        output: process.stdout
+    });
+    rl.question('Enter the code from that page here: ', function (code) {
+        rl.close();
+        oauth2Client.getToken(code, function (err, token) {
+            if (err) {
+                console.log('Error while trying to retrieve access token', err);
+                return;
+            }
+            oauth2Client.credentials = token;
+            storeToken(token);
+            callback(oauth2Client);
+        });
+    });
+}
+
+/**
+ * Store token to disk be used in later program executions.
+ *
+ * @param {Object} token The token to store to disk.
+ */
+function storeToken(token) {
+    try {
+        fs.mkdirSync(TOKEN_DIR);
+    } catch (err) {
+        if (err.code != 'EEXIST') {
+            throw err;
+        }
+    }
+    fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
+        if (err) throw err;
+        console.log('Token stored to ' + TOKEN_PATH);
+    });
+    console.log('Token stored to ' + TOKEN_PATH);
+}
+
+/**
+ * Lists the names and IDs of up to 10 files.
+ *
+ * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
+ */
+function getChannel(auth) {
+    var service = google.youtube('v3');
+    service.channels.list({
+        auth: auth,
+        part: 'snippet,contentDetails,statistics',
+        forUsername: 'GoogleDevelopers'
+    }, function (err, response) {
+        if (err) {
+            console.log('The API returned an error: ' + err);
+            return;
+        }
+        var channels = response.data.items;
+        if (channels.length == 0) {
+            console.log('No channel found.');
+        } else {
+            console.log('This channel\'s ID is %s. Its title is \'%s\', and ' +
+                'it has %s views.',
+                channels[0].id,
+                channels[0].snippet.title,
+                channels[0].statistics.viewCount);
+        }
+    });
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 530f38e60d6289a221a463ba36af2ed22c15d8d2 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Wed, 26 Jun 2019 17:54:16 -0400
Subject: Video Search Sample

---
 src/client/DocServer.ts                   |  4 ++++
 src/client/apis/youtube/YoutubeBox.tsx    |  1 +
 src/server/Message.ts                     |  2 +-
 src/server/index.ts                       |  2 ++
 src/server/youtubeApi/youtubeApiSample.js | 25 ++++++++++++++++++++++++-
 5 files changed, 32 insertions(+), 2 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 9dae54d74..b0060bfdc 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -52,6 +52,10 @@ export namespace DocServer {
         return apiKey;
     }
 
+    export function getYoutubeVideos() {
+        Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, YoutubeQueryTypes.SearchVideo);
+    }
+
 
     export async function GetRefFields(ids: string[]): Promise<{ [id: string]: Opt<RefField> }> {
         const requestedIds: string[] = [];
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index b029c51ec..dce891a07 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -19,6 +19,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
 
     componentWillMount() {
         DocServer.getYoutubeChannels();
+        DocServer.getYoutubeVideos();
     }
 
     _ignore = 0;
diff --git a/src/server/Message.ts b/src/server/Message.ts
index 0fc5dd4b5..87bb9d0fc 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -25,7 +25,7 @@ export interface Transferable {
 }
 
 export enum YoutubeQueryTypes {
-    Channels
+    Channels, SearchVideo
 }
 
 export interface Reference {
diff --git a/src/server/index.ts b/src/server/index.ts
index b36cb0bf2..3d4f59ee4 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -372,6 +372,8 @@ function HandleYoutubeQuery([type, callback]: [YoutubeQueryType, (result?: strin
         case YoutubeQueryType.Channels:
             YoutubeApi.authorizedGetChannel(youtubeApiKey);
             break;
+        case YoutubeQueryType.SearchVideo:
+            YoutubeApi.authorizedGetVideos(youtubeApiKey);
     }
 }
 
diff --git a/src/server/youtubeApi/youtubeApiSample.js b/src/server/youtubeApi/youtubeApiSample.js
index 7d5c936f5..35d74c62f 100644
--- a/src/server/youtubeApi/youtubeApiSample.js
+++ b/src/server/youtubeApi/youtubeApiSample.js
@@ -23,11 +23,16 @@ module.exports.readApiKey = (callback) => {
 
 module.exports.authorizedGetChannel = (apiKey) => {
     //this didnt get called
-    console.log("I get called");
+    console.log("I get called   ", apiKey);
+    console.log(TOKEN_PATH);
     // Authorize a client with the loaded credentials, then call the YouTube API.
     authorize(JSON.parse(apiKey), getChannel);
 }
 
+module.exports.authorizedGetVideos = (apiKey) => {
+    authorize(JSON.parse(apiKey), getSampleVideos);
+}
+
 
 /**
  * Create an OAuth2 client with the given credentials, and then execute the
@@ -132,4 +137,22 @@ function getChannel(auth) {
                 channels[0].statistics.viewCount);
         }
     });
+}
+
+function getSampleVideos(auth) {
+    let service = google.youtube('v3');
+    service.search.list({
+        auth: auth,
+        part: 'id, snippet',
+        type: 'video',
+        q: 'istanbul',
+        maxResults: 3
+    }, function (err, response) {
+        if (err) {
+            console.log('The API returned an error: ' + err);
+            return;
+        }
+        let videos = response.data.items;
+        console.log('Videos found: ' + videos[0].id.videoId, " ", videos[0].snippet.title);
+    });
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 21bc14319013e4757ca24f56a685b7d75eaa259a Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Wed, 26 Jun 2019 19:15:50 -0400
Subject: Searching through document for a youtube video done

---
 src/client/DocServer.ts                   |  6 +++---
 src/client/apis/youtube/YoutubeBox.tsx    | 26 +++++++++++++++-----------
 src/server/Message.ts                     |  7 ++++++-
 src/server/index.ts                       |  8 ++++----
 src/server/youtubeApi/youtubeApiSample.js | 12 ++++++------
 5 files changed, 34 insertions(+), 25 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index b0060bfdc..65d662ebc 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -48,12 +48,12 @@ export namespace DocServer {
     }
 
     export async function getYoutubeChannels() {
-        let apiKey = await Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, YoutubeQueryTypes.Channels);
+        let apiKey = await Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.Channels });
         return apiKey;
     }
 
-    export function getYoutubeVideos() {
-        Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, YoutubeQueryTypes.SearchVideo);
+    export function getYoutubeVideos(videoTitle: string) {
+        Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.SearchVideo, userInput: videoTitle });
     }
 
 
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index dce891a07..b044e2a05 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -4,7 +4,7 @@ import { FieldViewProps, FieldView } from "../../views/nodes/FieldView";
 import { HtmlField } from "../../../new_fields/HtmlField";
 import { WebField } from "../../../new_fields/URLField";
 import { observer } from "mobx-react";
-import { computed, reaction, IReactionDisposer } from 'mobx';
+import { computed, reaction, IReactionDisposer, observable } from 'mobx';
 import { DocumentDecorations } from "../../views/DocumentDecorations";
 import { InkingControl } from "../../views/InkingControl";
 import { Utils } from "../../../Utils";
@@ -14,12 +14,12 @@ import { DocServer } from "../../DocServer";
 @observer
 export class YoutubeBox extends React.Component<FieldViewProps> {
 
+    @observable YoutubeSearchElement: HTMLInputElement | undefined;
 
     public static LayoutString() { return FieldView.LayoutString(YoutubeBox); }
 
     componentWillMount() {
         DocServer.getYoutubeChannels();
-        DocServer.getYoutubeVideos();
     }
 
     _ignore = 0;
@@ -39,19 +39,23 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
             e.stopPropagation();
         }
     }
+
+    onEnterKeyDown = (e: React.KeyboardEvent) => {
+        if (e.keyCode === 13) {
+            let submittedTitle = this.YoutubeSearchElement!.value;
+            console.log(submittedTitle);
+            this.YoutubeSearchElement!.value = "";
+            this.YoutubeSearchElement!.blur();
+            DocServer.getYoutubeVideos(submittedTitle);
+
+        }
+    }
+
     render() {
         let field = this.props.Document[this.props.fieldKey];
-        let view;
-        if (field instanceof HtmlField) {
-            view = <span id="webBox-htmlSpan" dangerouslySetInnerHTML={{ __html: field.html }} />;
-        } else if (field instanceof WebField) {
-            view = <iframe src={field.url.href} style={{ position: "absolute", width: "100%", height: "100%" }} />;
-        } else {
-            view = <iframe src={"https://crossorigin.me/https://cs.brown.edu"} style={{ position: "absolute", width: "100%", height: "100%" }} />;
-        }
         let content =
             <div style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
-                {view}
+                <input type="text" placeholder="Search for a video" onKeyDown={this.onEnterKeyDown} style={{ width: "100%", border: "1px solid black", padding: 5, textAlign: "center" }} ref={(e) => this.YoutubeSearchElement = e!} />
             </div>;
 
         let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
diff --git a/src/server/Message.ts b/src/server/Message.ts
index 87bb9d0fc..7b208dee9 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -28,6 +28,11 @@ export enum YoutubeQueryTypes {
     Channels, SearchVideo
 }
 
+export interface YoutubeQueryInput {
+    readonly type: YoutubeQueryTypes;
+    readonly userInput?: string;
+}
+
 export interface Reference {
     readonly id: string;
 }
@@ -49,5 +54,5 @@ export namespace MessageStore {
     export const GetRefFields = new Message<string[]>("Get Ref Fields");
     export const UpdateField = new Message<Diff>("Update Ref Field");
     export const CreateField = new Message<Reference>("Create Ref Field");
-    export const YoutubeApiQuery = new Message<YoutubeQueryTypes>("Youtube Api Query");
+    export const YoutubeApiQuery = new Message<YoutubeQueryInput>("Youtube Api Query");
 }
diff --git a/src/server/index.ts b/src/server/index.ts
index 3d4f59ee4..9faeee381 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -24,7 +24,7 @@ import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLo
 import { DashUserModel } from './authentication/models/user_model';
 import { Client } from './Client';
 import { Database } from './database';
-import { MessageStore, Transferable, Types, Diff, YoutubeQueryTypes as YoutubeQueryType } from "./Message";
+import { MessageStore, Transferable, Types, Diff, YoutubeQueryTypes as YoutubeQueryType, YoutubeQueryInput } from "./Message";
 import { RouteStore } from './RouteStore';
 const app = express();
 const config = require('../../webpack.config');
@@ -367,13 +367,13 @@ function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => v
     Database.Instance.getDocuments(ids, callback, "newDocuments");
 }
 
-function HandleYoutubeQuery([type, callback]: [YoutubeQueryType, (result?: string) => void]) {
-    switch (type) {
+function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: string) => void]) {
+    switch (query.type) {
         case YoutubeQueryType.Channels:
             YoutubeApi.authorizedGetChannel(youtubeApiKey);
             break;
         case YoutubeQueryType.SearchVideo:
-            YoutubeApi.authorizedGetVideos(youtubeApiKey);
+            YoutubeApi.authorizedGetVideos(youtubeApiKey, query.userInput);
     }
 }
 
diff --git a/src/server/youtubeApi/youtubeApiSample.js b/src/server/youtubeApi/youtubeApiSample.js
index 35d74c62f..cd2e89cae 100644
--- a/src/server/youtubeApi/youtubeApiSample.js
+++ b/src/server/youtubeApi/youtubeApiSample.js
@@ -29,8 +29,8 @@ module.exports.authorizedGetChannel = (apiKey) => {
     authorize(JSON.parse(apiKey), getChannel);
 }
 
-module.exports.authorizedGetVideos = (apiKey) => {
-    authorize(JSON.parse(apiKey), getSampleVideos);
+module.exports.authorizedGetVideos = (apiKey, userInput) => {
+    authorize(JSON.parse(apiKey), getSampleVideos, { userInput: userInput });
 }
 
 
@@ -41,7 +41,7 @@ module.exports.authorizedGetVideos = (apiKey) => {
  * @param {Object} credentials The authorization client credentials.
  * @param {function} callback The callback to call with the authorized client.
  */
-function authorize(credentials, callback) {
+function authorize(credentials, callback, args = {}) {
     let clientSecret = credentials.installed.client_secret;
     let clientId = credentials.installed.client_id;
     let redirectUrl = credentials.installed.redirect_uris[0];
@@ -53,7 +53,7 @@ function authorize(credentials, callback) {
             getNewToken(oauth2Client, callback);
         } else {
             oauth2Client.credentials = JSON.parse(token);
-            callback(oauth2Client);
+            callback(oauth2Client, args);
         }
     });
 }
@@ -139,13 +139,13 @@ function getChannel(auth) {
     });
 }
 
-function getSampleVideos(auth) {
+function getSampleVideos(auth, args) {
     let service = google.youtube('v3');
     service.search.list({
         auth: auth,
         part: 'id, snippet',
         type: 'video',
-        q: 'istanbul',
+        q: args.userInput,
         maxResults: 3
     }, function (err, response) {
         if (err) {
-- 
cgit v1.2.3-70-g09d2


From f31c0d97f9f59371d90d1396469aa9569933fb0d Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Thu, 27 Jun 2019 12:55:31 -0400
Subject: Youtube Results Showing as List Implemented

---
 src/client/DocServer.ts                   |  4 ++--
 src/client/apis/youtube/YoutubeBox.tsx    | 28 ++++++++++++++++++++++++++--
 src/server/index.ts                       |  4 ++--
 src/server/youtubeApi/youtubeApiSample.js |  5 +++--
 4 files changed, 33 insertions(+), 8 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 65d662ebc..4fb8b8b7b 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -52,8 +52,8 @@ export namespace DocServer {
         return apiKey;
     }
 
-    export function getYoutubeVideos(videoTitle: string) {
-        Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.SearchVideo, userInput: videoTitle });
+    export function getYoutubeVideos(videoTitle: string, callBack: (videos: any[]) => void) {
+        Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.SearchVideo, userInput: videoTitle }, callBack);
     }
 
 
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index b044e2a05..d4d37950e 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -4,7 +4,7 @@ import { FieldViewProps, FieldView } from "../../views/nodes/FieldView";
 import { HtmlField } from "../../../new_fields/HtmlField";
 import { WebField } from "../../../new_fields/URLField";
 import { observer } from "mobx-react";
-import { computed, reaction, IReactionDisposer, observable } from 'mobx';
+import { computed, reaction, IReactionDisposer, observable, action } from 'mobx';
 import { DocumentDecorations } from "../../views/DocumentDecorations";
 import { InkingControl } from "../../views/InkingControl";
 import { Utils } from "../../../Utils";
@@ -15,6 +15,8 @@ import { DocServer } from "../../DocServer";
 export class YoutubeBox extends React.Component<FieldViewProps> {
 
     @observable YoutubeSearchElement: HTMLInputElement | undefined;
+    @observable searchResultsFound: boolean = false;
+    @observable searchResults: any[] = [];
 
     public static LayoutString() { return FieldView.LayoutString(YoutubeBox); }
 
@@ -46,16 +48,38 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
             console.log(submittedTitle);
             this.YoutubeSearchElement!.value = "";
             this.YoutubeSearchElement!.blur();
-            DocServer.getYoutubeVideos(submittedTitle);
+            DocServer.getYoutubeVideos(submittedTitle, this.processesVideoResults);
 
         }
     }
 
+    @action
+    processesVideoResults = (videos: any[]) => {
+        this.searchResults = videos;
+        console.log("Callback got called");
+        if (this.searchResults.length > 0) {
+            this.searchResultsFound = true;
+        }
+    }
+
+    renderSearchResults = () => {
+        if (this.searchResultsFound) {
+            return <ul>
+                {this.searchResults.map((video) => {
+                    return <li key={video.id.videoId}>{video.snippet.title}</li>;
+                })}
+            </ul>;
+        } else {
+            return (null);
+        }
+    }
+
     render() {
         let field = this.props.Document[this.props.fieldKey];
         let content =
             <div style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
                 <input type="text" placeholder="Search for a video" onKeyDown={this.onEnterKeyDown} style={{ width: "100%", border: "1px solid black", padding: 5, textAlign: "center" }} ref={(e) => this.YoutubeSearchElement = e!} />
+                {this.renderSearchResults()}
             </div>;
 
         let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
diff --git a/src/server/index.ts b/src/server/index.ts
index 9faeee381..9e4ad9d86 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -367,13 +367,13 @@ function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => v
     Database.Instance.getDocuments(ids, callback, "newDocuments");
 }
 
-function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: string) => void]) {
+function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any[]) => void]) {
     switch (query.type) {
         case YoutubeQueryType.Channels:
             YoutubeApi.authorizedGetChannel(youtubeApiKey);
             break;
         case YoutubeQueryType.SearchVideo:
-            YoutubeApi.authorizedGetVideos(youtubeApiKey, query.userInput);
+            YoutubeApi.authorizedGetVideos(youtubeApiKey, query.userInput, callback);
     }
 }
 
diff --git a/src/server/youtubeApi/youtubeApiSample.js b/src/server/youtubeApi/youtubeApiSample.js
index cd2e89cae..e95f99015 100644
--- a/src/server/youtubeApi/youtubeApiSample.js
+++ b/src/server/youtubeApi/youtubeApiSample.js
@@ -29,8 +29,8 @@ module.exports.authorizedGetChannel = (apiKey) => {
     authorize(JSON.parse(apiKey), getChannel);
 }
 
-module.exports.authorizedGetVideos = (apiKey, userInput) => {
-    authorize(JSON.parse(apiKey), getSampleVideos, { userInput: userInput });
+module.exports.authorizedGetVideos = (apiKey, userInput, callBack) => {
+    authorize(JSON.parse(apiKey), getSampleVideos, { userInput: userInput, callBack: callBack });
 }
 
 
@@ -154,5 +154,6 @@ function getSampleVideos(auth, args) {
         }
         let videos = response.data.items;
         console.log('Videos found: ' + videos[0].id.videoId, " ", videos[0].snippet.title);
+        args.callBack(videos);
     });
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 9e410ba033cec8244e59ba184ec829cf5833fad8 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Thu, 27 Jun 2019 16:49:07 -0400
Subject: Searching and Clicking on Embed added

---
 src/client/apis/youtube/YoutubeBox.scss |  3 +++
 src/client/apis/youtube/YoutubeBox.tsx  | 28 ++++++++++++++++++++++------
 2 files changed, 25 insertions(+), 6 deletions(-)
 create mode 100644 src/client/apis/youtube/YoutubeBox.scss

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.scss b/src/client/apis/youtube/YoutubeBox.scss
new file mode 100644
index 000000000..962f814a2
--- /dev/null
+++ b/src/client/apis/youtube/YoutubeBox.scss
@@ -0,0 +1,3 @@
+li {
+    margin: 4px;
+}
\ No newline at end of file
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index d4d37950e..3e7e9e06d 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -9,6 +9,8 @@ import { DocumentDecorations } from "../../views/DocumentDecorations";
 import { InkingControl } from "../../views/InkingControl";
 import { Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
+import { NumCast } from "../../../new_fields/Types";
+import "./YoutubeBox.scss";
 
 
 @observer
@@ -17,6 +19,8 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     @observable YoutubeSearchElement: HTMLInputElement | undefined;
     @observable searchResultsFound: boolean = false;
     @observable searchResults: any[] = [];
+    @observable videoClicked: boolean = false;
+    @observable selectedVideoUrl: string = "";
 
     public static LayoutString() { return FieldView.LayoutString(YoutubeBox); }
 
@@ -45,7 +49,6 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     onEnterKeyDown = (e: React.KeyboardEvent) => {
         if (e.keyCode === 13) {
             let submittedTitle = this.YoutubeSearchElement!.value;
-            console.log(submittedTitle);
             this.YoutubeSearchElement!.value = "";
             this.YoutubeSearchElement!.blur();
             DocServer.getYoutubeVideos(submittedTitle, this.processesVideoResults);
@@ -56,30 +59,43 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     @action
     processesVideoResults = (videos: any[]) => {
         this.searchResults = videos;
-        console.log("Callback got called");
         if (this.searchResults.length > 0) {
             this.searchResultsFound = true;
+            this.searchResults.forEach((video) => console.log("Image Url", video.snippet));
+            if (this.videoClicked) {
+                this.videoClicked = false;
+            }
         }
     }
 
-    renderSearchResults = () => {
+    renderSearchResultsOrVideo = () => {
         if (this.searchResultsFound) {
             return <ul>
                 {this.searchResults.map((video) => {
-                    return <li key={video.id.videoId}>{video.snippet.title}</li>;
+                    return <li onClick={() => this.embedVideoOnClick(video.id.videoId)} key={video.id.videoId}><img src={video.snippet.thumbnails.medium.url} />  {video.snippet.title}</li>;
                 })}
             </ul>;
+        } else if (this.videoClicked) {
+            return <iframe src={this.selectedVideoUrl} height={NumCast(this.props.Document.height) - 40} width={NumCast(this.props.Document.width)}></iframe>;
         } else {
             return (null);
         }
     }
 
+    @action
+    embedVideoOnClick = (videoId: string) => {
+        let embeddedUrl = "https://www.youtube.com/embed/" + videoId;
+        this.selectedVideoUrl = embeddedUrl;
+        this.searchResultsFound = false;
+        this.videoClicked = true;
+    }
+
     render() {
         let field = this.props.Document[this.props.fieldKey];
         let content =
             <div style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
-                <input type="text" placeholder="Search for a video" onKeyDown={this.onEnterKeyDown} style={{ width: "100%", border: "1px solid black", padding: 5, textAlign: "center" }} ref={(e) => this.YoutubeSearchElement = e!} />
-                {this.renderSearchResults()}
+                <input type="text" placeholder="Search for a video" onKeyDown={this.onEnterKeyDown} style={{ height: 40, width: "100%", border: "1px solid black", padding: 5, textAlign: "center" }} ref={(e) => this.YoutubeSearchElement = e!} />
+                {this.renderSearchResultsOrVideo()}
             </div>;
 
         let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
-- 
cgit v1.2.3-70-g09d2


From 49edd4e6071d0ea84cd0a652d69acb826866c99b Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Wed, 17 Jul 2019 17:50:45 -0400
Subject: New VideoBox spawns when a youtube video search result is clicked

---
 src/client/apis/youtube/YoutubeBox.tsx    | 31 ++++++++++++++++++++++++-------
 src/server/youtubeApi/youtubeApiSample.js |  2 +-
 2 files changed, 25 insertions(+), 8 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 3e7e9e06d..e7913da9e 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -11,6 +11,7 @@ import { Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { NumCast } from "../../../new_fields/Types";
 import "./YoutubeBox.scss";
+import { Docs } from "../../documents/Documents";
 
 
 @observer
@@ -25,7 +26,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     public static LayoutString() { return FieldView.LayoutString(YoutubeBox); }
 
     componentWillMount() {
-        DocServer.getYoutubeChannels();
+        //DocServer.getYoutubeChannels();
     }
 
     _ignore = 0;
@@ -59,34 +60,50 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     @action
     processesVideoResults = (videos: any[]) => {
         this.searchResults = videos;
+        console.log("Results: ", this.searchResults);
         if (this.searchResults.length > 0) {
             this.searchResultsFound = true;
-            this.searchResults.forEach((video) => console.log("Image Url", video.snippet));
             if (this.videoClicked) {
                 this.videoClicked = false;
             }
         }
     }
 
+    filterYoutubeTitleResult = (resultTitle: string) => {
+        let processedTitle: string = resultTitle.ReplaceAll("&amp;", "&");
+        processedTitle = processedTitle.ReplaceAll("&#39;", "'");
+        processedTitle = processedTitle.ReplaceAll("&quot;", "\"");
+        return processedTitle;
+    }
+
     renderSearchResultsOrVideo = () => {
         if (this.searchResultsFound) {
             return <ul>
                 {this.searchResults.map((video) => {
-                    return <li onClick={() => this.embedVideoOnClick(video.id.videoId)} key={video.id.videoId}><img src={video.snippet.thumbnails.medium.url} />  {video.snippet.title}</li>;
+                    let filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
+                    return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={video.id.videoId}><img src={video.snippet.thumbnails.medium.url} />  {filteredTitle}</li>;
                 })}
             </ul>;
-        } else if (this.videoClicked) {
-            return <iframe src={this.selectedVideoUrl} height={NumCast(this.props.Document.height) - 40} width={NumCast(this.props.Document.width)}></iframe>;
+            // } else if (this.videoClicked) {
+            //     return <iframe src={this.selectedVideoUrl} height={NumCast(this.props.Document.height) - 40} width={NumCast(this.props.Document.width)}></iframe>;
+            // } 
         } else {
             return (null);
         }
     }
 
     @action
-    embedVideoOnClick = (videoId: string) => {
+    embedVideoOnClick = (videoId: string, filteredTitle: string) => {
         let embeddedUrl = "https://www.youtube.com/embed/" + videoId;
         this.selectedVideoUrl = embeddedUrl;
-        this.searchResultsFound = false;
+        let addFunction = this.props.addDocument!;
+        let newVideoX = NumCast(this.props.Document.x) + NumCast(this.props.Document.width);
+        let newVideoY = NumCast(this.props.Document.y) + NumCast(this.props.Document.height);
+
+        addFunction(Docs.Create.VideoDocument(embeddedUrl, { title: filteredTitle, width: 400, height: 315, x: newVideoX, y: newVideoY }));
+
+        //this.props.addDocument(Docs.Create.VideoDocument(embeddedUrl, { title: embeddedUrl, width: 400, height: 315 }));
+        //this.searchResultsFound = false;
         this.videoClicked = true;
     }
 
diff --git a/src/server/youtubeApi/youtubeApiSample.js b/src/server/youtubeApi/youtubeApiSample.js
index e95f99015..f875812d5 100644
--- a/src/server/youtubeApi/youtubeApiSample.js
+++ b/src/server/youtubeApi/youtubeApiSample.js
@@ -153,7 +153,7 @@ function getSampleVideos(auth, args) {
             return;
         }
         let videos = response.data.items;
-        console.log('Videos found: ' + videos[0].id.videoId, " ", videos[0].snippet.title);
+        console.log('Videos found: ' + videos[0].id.videoId, " ", unescape(videos[0].snippet.title));
         args.callBack(videos);
     });
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 1f1f857847cd9ffa0fdd5001c0dd72f06ba903c0 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Wed, 17 Jul 2019 20:26:00 -0400
Subject: Titles alligned

---
 src/client/apis/youtube/YoutubeBox.scss | 6 ++++++
 src/client/apis/youtube/YoutubeBox.tsx  | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.scss b/src/client/apis/youtube/YoutubeBox.scss
index e6ccfea90..23f264b95 100644
--- a/src/client/apis/youtube/YoutubeBox.scss
+++ b/src/client/apis/youtube/YoutubeBox.scss
@@ -5,9 +5,15 @@ ul {
 
 li {
     margin: 4px;
+    display: inline-flex;
 }
 
 li:hover {
     cursor: pointer;
     opacity: 0.8;
+}
+
+.videoTitle {
+    margin-left: 4px;
+    font-family: Arial, Helvetica, sans-serif;
 }
\ No newline at end of file
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index e7913da9e..d94f3785c 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -81,7 +81,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
             return <ul>
                 {this.searchResults.map((video) => {
                     let filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
-                    return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={video.id.videoId}><img src={video.snippet.thumbnails.medium.url} />  {filteredTitle}</li>;
+                    return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={video.id.videoId}><img src={video.snippet.thumbnails.medium.url} /> <span className="videoTitle">{filteredTitle}</span>  </li>;
                 })}
             </ul>;
             // } else if (this.videoClicked) {
-- 
cgit v1.2.3-70-g09d2


From 808443664d66dc5009aaace48420659cf98c6c47 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Thu, 18 Jul 2019 13:31:17 -0400
Subject: Youtube Search Results Backed Up, Key error is present

---
 src/client/apis/youtube/YoutubeBox.tsx | 112 +++++++++++++++++++++++++++++----
 1 file changed, 100 insertions(+), 12 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index d94f3785c..fa2d3fb53 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -4,14 +4,17 @@ import { FieldViewProps, FieldView } from "../../views/nodes/FieldView";
 import { HtmlField } from "../../../new_fields/HtmlField";
 import { WebField } from "../../../new_fields/URLField";
 import { observer } from "mobx-react";
-import { computed, reaction, IReactionDisposer, observable, action } from 'mobx';
+import { computed, reaction, IReactionDisposer, observable, action, runInAction } from 'mobx';
 import { DocumentDecorations } from "../../views/DocumentDecorations";
 import { InkingControl } from "../../views/InkingControl";
 import { Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
-import { NumCast } from "../../../new_fields/Types";
+import { NumCast, Cast, StrCast } from "../../../new_fields/Types";
 import "./YoutubeBox.scss";
 import { Docs } from "../../documents/Documents";
+import { Doc } from "../../../new_fields/Doc";
+import { listSpec } from "../../../new_fields/Schema";
+import { List } from "../../../new_fields/List";
 
 
 @observer
@@ -22,11 +25,43 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     @observable searchResults: any[] = [];
     @observable videoClicked: boolean = false;
     @observable selectedVideoUrl: string = "";
+    // @observable cachedResults: List<Doc> | undefined;
+    @observable lisOfBackUp: JSX.Element[] = [];
+
 
     public static LayoutString() { return FieldView.LayoutString(YoutubeBox); }
 
-    componentWillMount() {
+    async componentWillMount() {
         //DocServer.getYoutubeChannels();
+        let castedBackUpDocs = Cast(this.props.Document.cachedSearch, listSpec(Doc));
+        if (!castedBackUpDocs) {
+            this.props.Document.cachedSearch = castedBackUpDocs = new List<Doc>();
+        }
+        if (castedBackUpDocs.length !== 0) {
+            //let awaitedRes = await castedBackUpDocs;
+
+            this.searchResultsFound = true;
+
+            for (let videoBackUp of castedBackUpDocs) {
+                let curBackUp = await videoBackUp;
+                let videoId = StrCast(curBackUp.videoId);
+                let videoTitle = StrCast(curBackUp.videoTitle);
+                let thumbnailUrl = StrCast(curBackUp.thumbnailUrl);
+                runInAction(() => this.lisOfBackUp.push((
+                    <li
+                        onClick={() => this.embedVideoOnClick(videoId, videoTitle)}
+                        key={videoId}
+                    >
+                        <img src={thumbnailUrl} />
+                        <span className="videoTitle">{videoTitle}</span>
+                    </li>)
+                ));
+            }
+
+
+        }
+
+
     }
 
     _ignore = 0;
@@ -63,12 +98,24 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         console.log("Results: ", this.searchResults);
         if (this.searchResults.length > 0) {
             this.searchResultsFound = true;
+            this.backUpSearchResults(videos);
             if (this.videoClicked) {
                 this.videoClicked = false;
             }
         }
     }
 
+    backUpSearchResults = (videos: any[]) => {
+        let castedBackUpDocs = Cast(this.props.Document.cachedSearch, listSpec(Doc));
+        videos.forEach((video) => {
+            let videoBackUp = new Doc();
+            videoBackUp.videoId = video.id.videoId;
+            videoBackUp.videoTitle = this.filterYoutubeTitleResult(video.snippet.title);
+            videoBackUp.thumbnailUrl = video.snippet.thumbnails.medium.url;
+            castedBackUpDocs!.push(videoBackUp);
+        });
+    }
+
     filterYoutubeTitleResult = (resultTitle: string) => {
         let processedTitle: string = resultTitle.ReplaceAll("&amp;", "&");
         processedTitle = processedTitle.ReplaceAll("&#39;", "'");
@@ -76,17 +123,56 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         return processedTitle;
     }
 
+    // mapSearchResults = () => {
+    //     if (this.searchResults.length !== 0) {
+    //         console.log("Entered here");
+    //         return <ul>{
+    //             this.searchResults.map((video) => {
+    //                 let filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
+    //                 return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={video.id.videoId}><img src={video.snippet.thumbnails.medium.url} /> <span className="videoTitle">{filteredTitle}</span>  </li>;
+    //             })}
+    //         </ul>;
+    //     } else if (this.cachedResults!.length !== 0) {
+    //         return <ul>{
+    //             this.cachedResults!.map(async (videoBackUp) => {
+    //                 let curBackUp = await videoBackUp;
+    //                 let videoId = StrCast(curBackUp.videoId);
+    //                 let videoTitle = StrCast(curBackUp.videoTitle);
+    //                 let thumbnailUrl = StrCast(curBackUp.thumbnailUrl);
+    //                 return <li onClick={() => this.embedVideoOnClick(videoTitle, videoTitle)} key={videoId}><img src={thumbnailUrl} /> <span className="videoTitle">{videoTitle}</span>  </li>;
+    //             })}
+    //         </ul>;
+    //     }
+    // }
+
     renderSearchResultsOrVideo = () => {
         if (this.searchResultsFound) {
-            return <ul>
-                {this.searchResults.map((video) => {
-                    let filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
-                    return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={video.id.videoId}><img src={video.snippet.thumbnails.medium.url} /> <span className="videoTitle">{filteredTitle}</span>  </li>;
-                })}
-            </ul>;
-            // } else if (this.videoClicked) {
-            //     return <iframe src={this.selectedVideoUrl} height={NumCast(this.props.Document.height) - 40} width={NumCast(this.props.Document.width)}></iframe>;
-            // } 
+            if (this.searchResults.length !== 0) {
+                return <ul>
+                    {this.searchResults.map((video) => {
+                        let filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
+                        return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={video.id.videoId}><img src={video.snippet.thumbnails.medium.url} /> <span className="videoTitle">{filteredTitle}</span>  </li>;
+                    })}
+                </ul>;
+            } else if (this.lisOfBackUp.length !== 0) {
+                // let lis: JSX.Element[] = [];
+                // for (let videoBackUp of this.cachedResults!) {
+                //     let curBackUp = await videoBackUp;
+                //     let videoId = StrCast(curBackUp.videoId);
+                //     let videoTitle = StrCast(curBackUp.videoTitle);
+                //     let thumbnailUrl = StrCast(curBackUp.thumbnailUrl);
+                //     lis.push((
+                //         <li
+                //             onClick={() => this.embedVideoOnClick(videoTitle, videoTitle)}
+                //             key={videoId}
+                //         >
+                //             <img src={thumbnailUrl} />
+                //             <span className="videoTitle">{videoTitle}</span>
+                //         </li>)
+                //     );
+                // }
+                return <ul>{this.lisOfBackUp}</ul>;
+            }
         } else {
             return (null);
         }
@@ -95,6 +181,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     @action
     embedVideoOnClick = (videoId: string, filteredTitle: string) => {
         let embeddedUrl = "https://www.youtube.com/embed/" + videoId;
+        console.log("EmbeddedUrl: ", embeddedUrl);
         this.selectedVideoUrl = embeddedUrl;
         let addFunction = this.props.addDocument!;
         let newVideoX = NumCast(this.props.Document.x) + NumCast(this.props.Document.width);
@@ -109,6 +196,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
 
     render() {
         let field = this.props.Document[this.props.fieldKey];
+        //let results = this.renderSearchResultsOrVideo();
         let content =
             <div style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
                 <input type="text" placeholder="Search for a video" onKeyDown={this.onEnterKeyDown} style={{ height: 40, width: "100%", border: "1px solid black", padding: 5, textAlign: "center" }} ref={(e) => this.YoutubeSearchElement = e!} />
-- 
cgit v1.2.3-70-g09d2


From 421311806a686dd0de2bbdd7d8aa7dbb5c9fe9d5 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Thu, 18 Jul 2019 14:14:43 -0400
Subject: Overriding allowed, keys problem still exist

---
 src/client/apis/youtube/YoutubeBox.tsx | 54 ++++------------------------------
 1 file changed, 5 insertions(+), 49 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index fa2d3fb53..33d989b6a 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -25,7 +25,6 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     @observable searchResults: any[] = [];
     @observable videoClicked: boolean = false;
     @observable selectedVideoUrl: string = "";
-    // @observable cachedResults: List<Doc> | undefined;
     @observable lisOfBackUp: JSX.Element[] = [];
 
 
@@ -38,7 +37,6 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
             this.props.Document.cachedSearch = castedBackUpDocs = new List<Doc>();
         }
         if (castedBackUpDocs.length !== 0) {
-            //let awaitedRes = await castedBackUpDocs;
 
             this.searchResultsFound = true;
 
@@ -50,7 +48,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
                 runInAction(() => this.lisOfBackUp.push((
                     <li
                         onClick={() => this.embedVideoOnClick(videoId, videoTitle)}
-                        key={videoId}
+                        key={Utils.GenerateGuid()}
                     >
                         <img src={thumbnailUrl} />
                         <span className="videoTitle">{videoTitle}</span>
@@ -95,7 +93,6 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     @action
     processesVideoResults = (videos: any[]) => {
         this.searchResults = videos;
-        console.log("Results: ", this.searchResults);
         if (this.searchResults.length > 0) {
             this.searchResultsFound = true;
             this.backUpSearchResults(videos);
@@ -106,13 +103,14 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     }
 
     backUpSearchResults = (videos: any[]) => {
-        let castedBackUpDocs = Cast(this.props.Document.cachedSearch, listSpec(Doc));
+        let newCachedList = new List<Doc>();
+        this.props.Document.cachedSearch = newCachedList;
         videos.forEach((video) => {
             let videoBackUp = new Doc();
             videoBackUp.videoId = video.id.videoId;
             videoBackUp.videoTitle = this.filterYoutubeTitleResult(video.snippet.title);
             videoBackUp.thumbnailUrl = video.snippet.thumbnails.medium.url;
-            castedBackUpDocs!.push(videoBackUp);
+            newCachedList.push(videoBackUp);
         });
     }
 
@@ -123,54 +121,16 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         return processedTitle;
     }
 
-    // mapSearchResults = () => {
-    //     if (this.searchResults.length !== 0) {
-    //         console.log("Entered here");
-    //         return <ul>{
-    //             this.searchResults.map((video) => {
-    //                 let filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
-    //                 return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={video.id.videoId}><img src={video.snippet.thumbnails.medium.url} /> <span className="videoTitle">{filteredTitle}</span>  </li>;
-    //             })}
-    //         </ul>;
-    //     } else if (this.cachedResults!.length !== 0) {
-    //         return <ul>{
-    //             this.cachedResults!.map(async (videoBackUp) => {
-    //                 let curBackUp = await videoBackUp;
-    //                 let videoId = StrCast(curBackUp.videoId);
-    //                 let videoTitle = StrCast(curBackUp.videoTitle);
-    //                 let thumbnailUrl = StrCast(curBackUp.thumbnailUrl);
-    //                 return <li onClick={() => this.embedVideoOnClick(videoTitle, videoTitle)} key={videoId}><img src={thumbnailUrl} /> <span className="videoTitle">{videoTitle}</span>  </li>;
-    //             })}
-    //         </ul>;
-    //     }
-    // }
-
     renderSearchResultsOrVideo = () => {
         if (this.searchResultsFound) {
             if (this.searchResults.length !== 0) {
                 return <ul>
                     {this.searchResults.map((video) => {
                         let filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
-                        return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={video.id.videoId}><img src={video.snippet.thumbnails.medium.url} /> <span className="videoTitle">{filteredTitle}</span>  </li>;
+                        return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={Utils.GenerateGuid()}><img src={video.snippet.thumbnails.medium.url} /> <span className="videoTitle">{filteredTitle}</span>  </li>;
                     })}
                 </ul>;
             } else if (this.lisOfBackUp.length !== 0) {
-                // let lis: JSX.Element[] = [];
-                // for (let videoBackUp of this.cachedResults!) {
-                //     let curBackUp = await videoBackUp;
-                //     let videoId = StrCast(curBackUp.videoId);
-                //     let videoTitle = StrCast(curBackUp.videoTitle);
-                //     let thumbnailUrl = StrCast(curBackUp.thumbnailUrl);
-                //     lis.push((
-                //         <li
-                //             onClick={() => this.embedVideoOnClick(videoTitle, videoTitle)}
-                //             key={videoId}
-                //         >
-                //             <img src={thumbnailUrl} />
-                //             <span className="videoTitle">{videoTitle}</span>
-                //         </li>)
-                //     );
-                // }
                 return <ul>{this.lisOfBackUp}</ul>;
             }
         } else {
@@ -188,15 +148,11 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         let newVideoY = NumCast(this.props.Document.y) + NumCast(this.props.Document.height);
 
         addFunction(Docs.Create.VideoDocument(embeddedUrl, { title: filteredTitle, width: 400, height: 315, x: newVideoX, y: newVideoY }));
-
-        //this.props.addDocument(Docs.Create.VideoDocument(embeddedUrl, { title: embeddedUrl, width: 400, height: 315 }));
-        //this.searchResultsFound = false;
         this.videoClicked = true;
     }
 
     render() {
         let field = this.props.Document[this.props.fieldKey];
-        //let results = this.renderSearchResultsOrVideo();
         let content =
             <div style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
                 <input type="text" placeholder="Search for a video" onKeyDown={this.onEnterKeyDown} style={{ height: 40, width: "100%", border: "1px solid black", padding: 5, textAlign: "center" }} ref={(e) => this.YoutubeSearchElement = e!} />
-- 
cgit v1.2.3-70-g09d2


From 82a9c1f854fad05db0878717aa82572ffc1290c1 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Thu, 18 Jul 2019 18:08:07 -0400
Subject: Update on coordinates

---
 src/client/apis/youtube/YoutubeBox.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 33d989b6a..da3c4b851 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -144,7 +144,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         console.log("EmbeddedUrl: ", embeddedUrl);
         this.selectedVideoUrl = embeddedUrl;
         let addFunction = this.props.addDocument!;
-        let newVideoX = NumCast(this.props.Document.x) + NumCast(this.props.Document.width);
+        let newVideoX = NumCast(this.props.Document.x);
         let newVideoY = NumCast(this.props.Document.y) + NumCast(this.props.Document.height);
 
         addFunction(Docs.Create.VideoDocument(embeddedUrl, { title: filteredTitle, width: 400, height: 315, x: newVideoX, y: newVideoY }));
-- 
cgit v1.2.3-70-g09d2


From 157060f7e6029c76765aa20d8fdbe325401a3880 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Fri, 19 Jul 2019 18:29:03 -0400
Subject: Youtube Search UI imitated mostly

---
 src/client/apis/youtube/YoutubeBox.scss | 74 +++++++++++++++++++++++++--
 src/client/apis/youtube/YoutubeBox.tsx  | 89 ++++++++++++++++++++++++++++++++-
 2 files changed, 159 insertions(+), 4 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.scss b/src/client/apis/youtube/YoutubeBox.scss
index 23f264b95..5b539b463 100644
--- a/src/client/apis/youtube/YoutubeBox.scss
+++ b/src/client/apis/youtube/YoutubeBox.scss
@@ -1,5 +1,6 @@
 ul {
     list-style-type: none;
+    padding-inline-start: 10px;
 }
 
 
@@ -13,7 +14,74 @@ li:hover {
     opacity: 0.8;
 }
 
-.videoTitle {
-    margin-left: 4px;
-    font-family: Arial, Helvetica, sans-serif;
+.search_wrapper {
+    width: 100%;
+    display: inline-flex;
+    height: 175px;
+
+    .textual_info {
+        font-family: Arial, Helvetica, sans-serif;
+
+        .videoTitle {
+            margin-left: 4px;
+            // display: inline-block;
+            color: #0D0D0D;
+            -webkit-line-clamp: 2;
+            display: block;
+            max-height: 4.8rem;
+            overflow: hidden;
+            font-size: 1.8rem;
+            font-weight: 400;
+            line-height: 2.4rem;
+            -webkit-box-orient: vertical;
+            text-overflow: ellipsis;
+            white-space: normal;
+            display: -webkit-box;
+        }
+
+        .channelName {
+            color:#606060;
+            margin-left: 4px;
+            font-size: 1.3rem;
+            font-weight: 400;
+            line-height: 1.8rem;
+            text-transform: none;
+            margin-top: 0px;
+            display: inline-block;
+        }
+
+        .video_description {
+            margin-left: 4px;
+            // font-size: 12px;
+            color: #606060;
+            padding-top: 8px;
+            margin-bottom: 8px;
+            display: block;
+            line-height: 1.8rem;
+            max-height: 4.2rem;
+            overflow: hidden;
+            font-size: 1.3rem;
+            font-weight: 400;
+            text-transform: none;
+        }
+
+        .publish_time {
+            //display: inline-block;
+            margin-left: 8px;
+            padding: 0;
+            border: 0;
+            background: transparent;
+            color: #606060;
+            max-width: 100%;
+            line-height: 1.8rem;
+            max-height: 3.6rem;
+            overflow: hidden;
+            font-size: 1.3rem;
+            font-weight: 400;
+            text-transform: none;
+        }
+        
+            
+        
+    }
 }
\ No newline at end of file
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index da3c4b851..7ac8d06f6 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -121,13 +121,100 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         return processedTitle;
     }
 
+    roundPublishTime = (publishTime: string) => {
+        let date = new Date(publishTime);
+        let curDate = new Date();
+        let videoYearDif = curDate.getFullYear() - date.getFullYear();
+        let videoMonthDif = curDate.getMonth() - date.getMonth();
+        let videoDayDif = curDate.getDay() - date.getDay();
+        console.log("video day dif: ", videoDayDif, " first day: ", curDate.getDay(), " second day: ", date.getDay());
+        let videoHoursDif = curDate.getHours() - date.getHours();
+        let videoMinutesDif = curDate.getMinutes() - date.getMinutes();
+        let videoSecondsDif = curDate.getSeconds() - date.getSeconds();
+        if (videoYearDif !== 0) {
+            return videoYearDif + " years ago";
+        } else if (videoMonthDif !== 0) {
+            return videoMonthDif + " months ago";
+        } else if (videoDayDif !== 0) {
+            return videoDayDif + " days ago";
+        } else if (videoHoursDif !== 0) {
+            return videoHoursDif + " hours ago";
+        } else if (videoMinutesDif) {
+            return videoMinutesDif + " minutes ago";
+        } else if (videoSecondsDif) {
+            return videoSecondsDif + " seconds ago";
+        }
+
+        console.log("Date : ", date);
+    }
+
+    roundPublishTime2 = (publishTime: string) => {
+        let date = new Date(publishTime).getTime();
+        let curDate = new Date().getTime();
+        let timeDif = curDate - date;
+        let totalSeconds = timeDif / 1000;
+        let totalMin = totalSeconds / 60;
+        let totalHours = totalMin / 60;
+        let totalDays = totalHours / 24;
+        let totalMonths = totalDays / 30.417;
+        let totalYears = totalMonths / 12;
+
+
+        let truncYears = Math.trunc(totalYears);
+        let truncMonths = Math.trunc(totalMonths);
+        let truncDays = Math.trunc(totalDays);
+        let truncHours = Math.trunc(totalHours);
+        let truncMin = Math.trunc(totalMin);
+        let truncSec = Math.trunc(totalSeconds);
+
+        let pluralCase = "";
+
+        if (truncYears !== 0) {
+            truncYears > 1 ? pluralCase = "s" : pluralCase = "";
+            return truncYears + " year" + pluralCase + " ago";
+        } else if (truncMonths !== 0) {
+            truncMonths > 1 ? pluralCase = "s" : pluralCase = "";
+            return truncMonths + " month" + pluralCase + " ago";
+        } else if (truncDays !== 0) {
+            truncDays > 1 ? pluralCase = "s" : pluralCase = "";
+            return truncDays + " day" + pluralCase + " ago";
+        } else if (truncHours !== 0) {
+            truncHours > 1 ? pluralCase = "s" : pluralCase = "";
+            return truncHours + " hour" + pluralCase + " ago";
+        } else if (truncMin !== 0) {
+            truncMin > 1 ? pluralCase = "s" : pluralCase = "";
+            return truncMin + " minute" + pluralCase + " ago";
+        } else if (truncSec !== 0) {
+            truncSec > 1 ? pluralCase = "s" : pluralCase = "";
+            return truncSec + " second" + pluralCase + " ago";
+        }
+    }
+
     renderSearchResultsOrVideo = () => {
         if (this.searchResultsFound) {
             if (this.searchResults.length !== 0) {
                 return <ul>
                     {this.searchResults.map((video) => {
                         let filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
-                        return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={Utils.GenerateGuid()}><img src={video.snippet.thumbnails.medium.url} /> <span className="videoTitle">{filteredTitle}</span>  </li>;
+                        let channelTitle = video.snippet.channelTitle;
+                        let videoDescription = video.snippet.description;
+                        let pusblishDate = this.roundPublishTime2(video.snippet.publishedAt);
+                        // let duration = video.contentDetails.duration;
+                        //let viewCount = video.statistics.viewCount;
+                        //this.roundPublishTime(pusblishDate);
+                        //this.roundPublishTime2(video.snippet.publishedAt);
+                        return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={Utils.GenerateGuid()}>
+                            <div className="search_wrapper">
+                                <img src={video.snippet.thumbnails.medium.url} />
+                                <div className="textual_info">
+                                    <span className="videoTitle">{filteredTitle}</span>
+                                    <span className="channelName">{channelTitle}</span>
+                                    <span className="publish_time">{pusblishDate}</span>
+                                    {/* <h6 className="viewCount">{viewCount}</h6> */}
+                                    <p className="video_description">{videoDescription}</p>
+                                </div>
+                            </div>
+                        </li>;
                     })}
                 </ul>;
             } else if (this.lisOfBackUp.length !== 0) {
-- 
cgit v1.2.3-70-g09d2


From 4446a3a52c4cf4b03c201ab2d6a9179647686e40 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Mon, 22 Jul 2019 18:47:14 -0400
Subject: Pulled Duration and ViewCount details, Need to csss duration

---
 src/client/DocServer.ts                   |  4 ++
 src/client/apis/youtube/YoutubeBox.scss   | 37 ++++++++++++++++++
 src/client/apis/youtube/YoutubeBox.tsx    | 64 ++++++++++++++++++++++++++++---
 src/server/Message.ts                     |  3 +-
 src/server/index.ts                       |  2 +
 src/server/youtubeApi/youtubeApiSample.js | 21 ++++++++++
 6 files changed, 125 insertions(+), 6 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index bc5819061..8a9abb514 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -168,6 +168,10 @@ export namespace DocServer {
         Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.SearchVideo, userInput: videoTitle }, callBack);
     }
 
+    export function getYoutubeVideoDetails(videoIds: string, callBack: (videoDetails: any[]) => void) {
+        Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.VideoDetails, videoIds: videoIds }, callBack);
+    }
+
 
     /**
      * Given a list of Doc GUIDs, this utility function will asynchronously attempt to each id's associated
diff --git a/src/client/apis/youtube/YoutubeBox.scss b/src/client/apis/youtube/YoutubeBox.scss
index 5b539b463..00979f945 100644
--- a/src/client/apis/youtube/YoutubeBox.scss
+++ b/src/client/apis/youtube/YoutubeBox.scss
@@ -19,6 +19,27 @@ li:hover {
     display: inline-flex;
     height: 175px;
 
+    .video_duration {
+        margin: 0;
+        padding: 0;
+        border: 0;
+        background: transparent;
+        display: inline-block;
+        position: absolute;
+        bottom: 0;
+        right: 0;
+        margin: 4px;
+        color: #FFFFFF;
+        background-color: rgba(0, 0, 0, 0.80);
+        padding: 2px 4px;
+        border-radius: 2px;
+        letter-spacing: .5px;
+        font-size: 1.2rem;
+        font-weight: 500;
+        line-height: 1.2rem;
+
+    }
+
     .textual_info {
         font-family: Arial, Helvetica, sans-serif;
 
@@ -80,6 +101,22 @@ li:hover {
             font-weight: 400;
             text-transform: none;
         }
+
+        .viewCount {
+
+            margin-left: 8px;
+            padding: 0;
+            border: 0;
+            background: transparent;
+            color: #606060;
+            max-width: 100%;
+            line-height: 1.8rem;
+            max-height: 3.6rem;
+            overflow: hidden;
+            font-size: 1.3rem;
+            font-weight: 400;
+            text-transform: none;
+        }
         
             
         
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 7ac8d06f6..824a0251d 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -26,12 +26,15 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     @observable videoClicked: boolean = false;
     @observable selectedVideoUrl: string = "";
     @observable lisOfBackUp: JSX.Element[] = [];
+    @observable videoIds: string | undefined;
+    @observable videoDetails: any[] = [];
 
 
     public static LayoutString() { return FieldView.LayoutString(YoutubeBox); }
 
     async componentWillMount() {
         //DocServer.getYoutubeChannels();
+        //DocServer.getYoutubeVideoDetails("Ks-_Mh1QhMc, 1NmvhSmN2uM", (results: any[]) => console.log("Details results: ", results));
         let castedBackUpDocs = Cast(this.props.Document.cachedSearch, listSpec(Doc));
         if (!castedBackUpDocs) {
             this.props.Document.cachedSearch = castedBackUpDocs = new List<Doc>();
@@ -95,6 +98,15 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         this.searchResults = videos;
         if (this.searchResults.length > 0) {
             this.searchResultsFound = true;
+            this.videoIds = "";
+            videos.forEach((video) => {
+                if (this.videoIds === "") {
+                    this.videoIds = video.id.videoId;
+                } else {
+                    this.videoIds = this.videoIds! + ", " + video.id.videoId;
+                }
+            });
+            DocServer.getYoutubeVideoDetails(this.videoIds, this.processVideoDetails);
             this.backUpSearchResults(videos);
             if (this.videoClicked) {
                 this.videoClicked = false;
@@ -102,6 +114,12 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         }
     }
 
+    @action
+    processVideoDetails = (videoDetails: any[]) => {
+        this.videoDetails = videoDetails;
+        console.log("Detail Res: ", this.videoDetails);
+    }
+
     backUpSearchResults = (videos: any[]) => {
         let newCachedList = new List<Doc>();
         this.props.Document.cachedSearch = newCachedList;
@@ -190,28 +208,64 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         }
     }
 
+    convertIsoTimeToDuration = (isoDur: string) => {
+
+        let convertedTime = isoDur.replace(/D|H|M/g, ":").replace(/P|T|S/g, "").split(":");
+
+        if (1 === convertedTime.length) {
+            2 !== convertedTime[0].length && (convertedTime[0] = "0" + convertedTime[0]), convertedTime[0] = "0:" + convertedTime[0];
+        } else {
+            for (var r = 1, l = convertedTime.length - 1; l >= r; r++) {
+                2 !== convertedTime[r].length && (convertedTime[r] = "0" + convertedTime[r]);
+            }
+        }
+
+        return convertedTime.join(":");
+    }
+
+    abbreviateViewCount = (viewCount: number) => {
+        if (viewCount < 1000) {
+            return viewCount.toString();
+        } else if (viewCount >= 1000 && viewCount < 1000000) {
+            return (Math.trunc(viewCount / 1000)) + "K";
+        } else if (viewCount >= 1000000 && viewCount < 1000000000) {
+            return (Math.trunc(viewCount / 1000000)) + "M";
+        } else if (viewCount >= 1000000000) {
+            return (Math.trunc(viewCount / 1000000000)) + "B";
+        }
+    }
+
     renderSearchResultsOrVideo = () => {
         if (this.searchResultsFound) {
             if (this.searchResults.length !== 0) {
                 return <ul>
-                    {this.searchResults.map((video) => {
+                    {this.searchResults.map((video, index) => {
                         let filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
                         let channelTitle = video.snippet.channelTitle;
                         let videoDescription = video.snippet.description;
                         let pusblishDate = this.roundPublishTime2(video.snippet.publishedAt);
-                        // let duration = video.contentDetails.duration;
-                        //let viewCount = video.statistics.viewCount;
+                        let duration;
+                        let viewCount;
+                        if (this.videoDetails.length !== 0) {
+                            duration = this.convertIsoTimeToDuration(this.videoDetails[index].contentDetails.duration);
+                            viewCount = this.abbreviateViewCount(this.videoDetails[index].statistics.viewCount);
+                        }
                         //this.roundPublishTime(pusblishDate);
                         //this.roundPublishTime2(video.snippet.publishedAt);
+
                         return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={Utils.GenerateGuid()}>
                             <div className="search_wrapper">
-                                <img src={video.snippet.thumbnails.medium.url} />
+                                <div style={{ backgroundColor: "yellow" }}>
+                                    <img src={video.snippet.thumbnails.medium.url} />
+                                    <span className="video_duration">{duration}</span>
+                                </div>
                                 <div className="textual_info">
                                     <span className="videoTitle">{filteredTitle}</span>
                                     <span className="channelName">{channelTitle}</span>
+                                    <span className="viewCount">{viewCount}</span>
                                     <span className="publish_time">{pusblishDate}</span>
-                                    {/* <h6 className="viewCount">{viewCount}</h6> */}
                                     <p className="video_description">{videoDescription}</p>
+
                                 </div>
                             </div>
                         </li>;
diff --git a/src/server/Message.ts b/src/server/Message.ts
index 1e29aef0b..aaee143e8 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -25,12 +25,13 @@ export interface Transferable {
 }
 
 export enum YoutubeQueryTypes {
-    Channels, SearchVideo
+    Channels, SearchVideo, VideoDetails
 }
 
 export interface YoutubeQueryInput {
     readonly type: YoutubeQueryTypes;
     readonly userInput?: string;
+    readonly videoIds?: string;
 }
 
 export interface Reference {
diff --git a/src/server/index.ts b/src/server/index.ts
index 60e34de8c..dfbc1a468 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -537,6 +537,8 @@ function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any
             break;
         case YoutubeQueryType.SearchVideo:
             YoutubeApi.authorizedGetVideos(youtubeApiKey, query.userInput, callback);
+        case YoutubeQueryType.VideoDetails:
+            YoutubeApi.authorizedGetVideoDetails(youtubeApiKey, query.videoIds, callback);
     }
 }
 
diff --git a/src/server/youtubeApi/youtubeApiSample.js b/src/server/youtubeApi/youtubeApiSample.js
index f875812d5..cf41a33e7 100644
--- a/src/server/youtubeApi/youtubeApiSample.js
+++ b/src/server/youtubeApi/youtubeApiSample.js
@@ -33,6 +33,10 @@ module.exports.authorizedGetVideos = (apiKey, userInput, callBack) => {
     authorize(JSON.parse(apiKey), getSampleVideos, { userInput: userInput, callBack: callBack });
 }
 
+module.exports.authorizedGetVideoDetails = (apiKey, videoIds, callBack) => {
+    authorize(JSON.parse(apiKey), getVideoDetails, { videoIds: videoIds, callBack: callBack });
+}
+
 
 /**
  * Create an OAuth2 client with the given credentials, and then execute the
@@ -156,4 +160,21 @@ function getSampleVideos(auth, args) {
         console.log('Videos found: ' + videos[0].id.videoId, " ", unescape(videos[0].snippet.title));
         args.callBack(videos);
     });
+}
+
+function getVideoDetails(auth, args) {
+    let service = google.youtube('v3');
+    service.videos.list({
+        auth: auth,
+        part: 'contentDetails, statistics',
+        id: args.videoIds
+    }, function (err, response) {
+        if (err) {
+            console.log('The API returned an error: ' + err);
+            return;
+        }
+        let videoDetails = response.data.items;
+        console.log('Video Details founds: ', videoDetails);
+        args.callBack(videoDetails);
+    });
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From e1b750da8faf8f00707de1b65efbd210c19fa723 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Tue, 23 Jul 2019 14:29:08 -0400
Subject: Store and css

---
 src/client/apis/youtube/YoutubeBox.scss | 10 +++++-----
 src/client/apis/youtube/YoutubeBox.tsx  | 23 +++++++++++++++++++++--
 2 files changed, 26 insertions(+), 7 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.scss b/src/client/apis/youtube/YoutubeBox.scss
index 00979f945..1fc91a9ae 100644
--- a/src/client/apis/youtube/YoutubeBox.scss
+++ b/src/client/apis/youtube/YoutubeBox.scss
@@ -20,14 +20,14 @@ li:hover {
     height: 175px;
 
     .video_duration {
-        margin: 0;
-        padding: 0;
+        // margin: 0;
+        // padding: 0;
         border: 0;
         background: transparent;
         display: inline-block;
-        position: absolute;
-        bottom: 0;
-        right: 0;
+        position: relative;
+        bottom: 25px;
+        left: 85%;
         margin: 4px;
         color: #FFFFFF;
         background-color: rgba(0, 0, 0, 0.80);
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 824a0251d..373eee5c4 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -12,7 +12,7 @@ import { DocServer } from "../../DocServer";
 import { NumCast, Cast, StrCast } from "../../../new_fields/Types";
 import "./YoutubeBox.scss";
 import { Docs } from "../../documents/Documents";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, DocListCastAsync } from "../../../new_fields/Doc";
 import { listSpec } from "../../../new_fields/Schema";
 import { List } from "../../../new_fields/List";
 
@@ -36,12 +36,29 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         //DocServer.getYoutubeChannels();
         //DocServer.getYoutubeVideoDetails("Ks-_Mh1QhMc, 1NmvhSmN2uM", (results: any[]) => console.log("Details results: ", results));
         let castedBackUpDocs = Cast(this.props.Document.cachedSearch, listSpec(Doc));
+        let castedSearchBackUp = Cast(this.props.Document.cachedSearchResults, Doc);
+        let awaitedBackUp = await castedSearchBackUp;
+
+        console.log("Backup results: ", awaitedBackUp);
+        console.log("Original Backup results: ", castedBackUpDocs);
+
+        let json = Cast(awaitedBackUp!.json, Doc);
+        let jsonList = await DocListCastAsync(json);
+        console.log("Fucked up list: ", jsonList);
+        for (let video of jsonList!) {
+            let videoId = await Cast(video.id, Doc);
+            let id = StrCast(videoId!.videoId);
+            console.log("ID: ", id);
+        }
+
+
+
         if (!castedBackUpDocs) {
             this.props.Document.cachedSearch = castedBackUpDocs = new List<Doc>();
         }
         if (castedBackUpDocs.length !== 0) {
 
-            this.searchResultsFound = true;
+            runInAction(() => this.searchResultsFound = true);
 
             for (let videoBackUp of castedBackUpDocs) {
                 let curBackUp = await videoBackUp;
@@ -121,6 +138,8 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     }
 
     backUpSearchResults = (videos: any[]) => {
+        console.log("Res: ", videos);
+        this.props.Document.cachedSearchResults = Docs.Get.DocumentHierarchyFromJson(videos, "videosBackUp");
         let newCachedList = new List<Doc>();
         this.props.Document.cachedSearch = newCachedList;
         videos.forEach((video) => {
-- 
cgit v1.2.3-70-g09d2


From 0591b8f1e60d1285fd9aac3e61160824948a166b Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Tue, 23 Jul 2019 17:33:31 -0400
Subject: Everything related to search stored

---
 src/client/apis/youtube/YoutubeBox.tsx    | 123 +++++++++++++++++++-----------
 src/client/documents/Documents.ts         |   2 +-
 src/server/youtubeApi/youtubeApiSample.js |   4 -
 3 files changed, 81 insertions(+), 48 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 373eee5c4..e630c11ae 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -16,6 +16,16 @@ import { Doc, DocListCastAsync } from "../../../new_fields/Doc";
 import { listSpec } from "../../../new_fields/Schema";
 import { List } from "../../../new_fields/List";
 
+interface VideoTemplate {
+    thumbnailUrl: string;
+    videoTitle: string;
+    videoId: string;
+    duration: string;
+    channelTitle: string;
+    viewCount: string;
+    publishDate: string;
+    videoDescription: string;
+}
 
 @observer
 export class YoutubeBox extends React.Component<FieldViewProps> {
@@ -28,58 +38,71 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     @observable lisOfBackUp: JSX.Element[] = [];
     @observable videoIds: string | undefined;
     @observable videoDetails: any[] = [];
+    @observable curVideoTemplates: VideoTemplate[] = [];
 
 
     public static LayoutString() { return FieldView.LayoutString(YoutubeBox); }
 
     async componentWillMount() {
         //DocServer.getYoutubeChannels();
-        //DocServer.getYoutubeVideoDetails("Ks-_Mh1QhMc, 1NmvhSmN2uM", (results: any[]) => console.log("Details results: ", results));
-        let castedBackUpDocs = Cast(this.props.Document.cachedSearch, listSpec(Doc));
         let castedSearchBackUp = Cast(this.props.Document.cachedSearchResults, Doc);
         let awaitedBackUp = await castedSearchBackUp;
+        let castedDetailBackUp = Cast(this.props.Document.cachedDetails, Doc);
+        let awaitedDetails = await castedDetailBackUp;
 
-        console.log("Backup results: ", awaitedBackUp);
-        console.log("Original Backup results: ", castedBackUpDocs);
-
-        let json = Cast(awaitedBackUp!.json, Doc);
-        let jsonList = await DocListCastAsync(json);
-        console.log("Fucked up list: ", jsonList);
-        for (let video of jsonList!) {
-            let videoId = await Cast(video.id, Doc);
-            let id = StrCast(videoId!.videoId);
-            console.log("ID: ", id);
-        }
 
 
+        let jsonList = await DocListCastAsync(awaitedBackUp!.json);
+        let jsonDetailList = await DocListCastAsync(awaitedDetails!.json);
 
-        if (!castedBackUpDocs) {
-            this.props.Document.cachedSearch = castedBackUpDocs = new List<Doc>();
-        }
-        if (castedBackUpDocs.length !== 0) {
-
+        if (jsonList!.length !== 0) {
             runInAction(() => this.searchResultsFound = true);
+            let index = 0;
+            for (let video of jsonList!) {
+
+                let videoId = await Cast(video.id, Doc);
+                let id = StrCast(videoId!.videoId);
+                let snippet = await Cast(video.snippet, Doc);
+                let videoTitle = this.filterYoutubeTitleResult(StrCast(snippet!.title));
+                let thumbnail = await Cast(snippet!.thumbnails, Doc);
+                let thumbnailMedium = await Cast(thumbnail!.medium, Doc);
+                let thumbnailUrl = StrCast(thumbnailMedium!.url);
+                let videoDescription = StrCast(snippet!.description);
+                let pusblishDate = (this.roundPublishTime2(StrCast(snippet!.publishedAt)))!;
+                let channelTitle = StrCast(snippet!.channelTitle);
+                let duration: string;
+                let viewCount: string;
+                if (jsonDetailList!.length !== 0) {
+                    let contentDetails = await Cast(jsonDetailList![index].contentDetails, Doc);
+                    let statistics = await Cast(jsonDetailList![index].statistics, Doc);
+                    duration = this.convertIsoTimeToDuration(StrCast(contentDetails!.duration));
+                    viewCount = this.abbreviateViewCount(NumCast(statistics!.viewCount))!;
+                }
+                index = index + 1;
+                let newTemplate: VideoTemplate = { videoId: id, videoTitle: videoTitle, thumbnailUrl: thumbnailUrl, publishDate: pusblishDate, channelTitle: channelTitle, videoDescription: videoDescription, duration: duration!, viewCount: viewCount! };
+                runInAction(() => this.curVideoTemplates.push(newTemplate));
+
+                // runInAction(() => this.lisOfBackUp.push((
+                //     <li onClick={() => this.embedVideoOnClick(id, videoTitle)} key={Utils.GenerateGuid() + id}>
+                //         <div className="search_wrapper">
+                //             <div style={{ backgroundColor: "yellow" }}>
+                //                 <img src={thumbnailUrl} />
+                //                 <span className="video_duration">{duration}</span>
+                //             </div>
+                //             <div className="textual_info">
+                //                 <span className="videoTitle">{videoTitle}</span>
+                //                 <span className="channelName">{channelTitle}</span>
+                //                 <span className="viewCount">{viewCount}</span>
+                //                 <span className="publish_time">{pusblishDate}</span>
+                //                 <p className="video_description">{videoDescription}</p>
+
+                //             </div>
+                //         </div>
+                //     </li>)
+                // ));
 
-            for (let videoBackUp of castedBackUpDocs) {
-                let curBackUp = await videoBackUp;
-                let videoId = StrCast(curBackUp.videoId);
-                let videoTitle = StrCast(curBackUp.videoTitle);
-                let thumbnailUrl = StrCast(curBackUp.thumbnailUrl);
-                runInAction(() => this.lisOfBackUp.push((
-                    <li
-                        onClick={() => this.embedVideoOnClick(videoId, videoTitle)}
-                        key={Utils.GenerateGuid()}
-                    >
-                        <img src={thumbnailUrl} />
-                        <span className="videoTitle">{videoTitle}</span>
-                    </li>)
-                ));
             }
-
-
         }
-
-
     }
 
     _ignore = 0;
@@ -134,11 +157,10 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     @action
     processVideoDetails = (videoDetails: any[]) => {
         this.videoDetails = videoDetails;
-        console.log("Detail Res: ", this.videoDetails);
+        this.props.Document.cachedDetails = Docs.Get.DocumentHierarchyFromJson(videoDetails, "detailBackUp");
     }
 
     backUpSearchResults = (videos: any[]) => {
-        console.log("Res: ", videos);
         this.props.Document.cachedSearchResults = Docs.Get.DocumentHierarchyFromJson(videos, "videosBackUp");
         let newCachedList = new List<Doc>();
         this.props.Document.cachedSearch = newCachedList;
@@ -164,7 +186,6 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         let videoYearDif = curDate.getFullYear() - date.getFullYear();
         let videoMonthDif = curDate.getMonth() - date.getMonth();
         let videoDayDif = curDate.getDay() - date.getDay();
-        console.log("video day dif: ", videoDayDif, " first day: ", curDate.getDay(), " second day: ", date.getDay());
         let videoHoursDif = curDate.getHours() - date.getHours();
         let videoMinutesDif = curDate.getMinutes() - date.getMinutes();
         let videoSecondsDif = curDate.getSeconds() - date.getSeconds();
@@ -182,7 +203,6 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
             return videoSecondsDif + " seconds ago";
         }
 
-        console.log("Date : ", date);
     }
 
     roundPublishTime2 = (publishTime: string) => {
@@ -290,8 +310,26 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
                         </li>;
                     })}
                 </ul>;
-            } else if (this.lisOfBackUp.length !== 0) {
-                return <ul>{this.lisOfBackUp}</ul>;
+            } else if (this.curVideoTemplates.length !== 0) {
+                return <ul>
+                    {this.curVideoTemplates.map((video: VideoTemplate) => {
+                        return <li onClick={() => this.embedVideoOnClick(video.videoId, video.videoTitle)} key={Utils.GenerateGuid()}>
+                            <div className="search_wrapper">
+                                <div style={{ backgroundColor: "yellow" }}>
+                                    <img src={video.thumbnailUrl} />
+                                    <span className="video_duration">{video.duration}</span>
+                                </div>
+                                <div className="textual_info">
+                                    <span className="videoTitle">{video.videoTitle}</span>
+                                    <span className="channelName">{video.channelTitle}</span>
+                                    <span className="viewCount">{video.viewCount}</span>
+                                    <span className="publish_time">{video.publishDate}</span>
+                                    <p className="video_description">{video.videoDescription}</p>
+                                </div>
+                            </div>
+                        </li>;
+                    })}
+                </ul>;
             }
         } else {
             return (null);
@@ -301,7 +339,6 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     @action
     embedVideoOnClick = (videoId: string, filteredTitle: string) => {
         let embeddedUrl = "https://www.youtube.com/embed/" + videoId;
-        console.log("EmbeddedUrl: ", embeddedUrl);
         this.selectedVideoUrl = embeddedUrl;
         let addFunction = this.props.addDocument!;
         let newVideoX = NumCast(this.props.Document.x);
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 191be9b7d..333e9859b 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -498,7 +498,7 @@ export namespace Docs {
         const convertObject = (object: any, title?: string): Doc => {
             let target = new Doc(), result: Opt<Field>;
             Object.keys(object).map(key => (result = toField(object[key], key)) && (target[key] = result));
-            title && (target.title = title);
+            title && !target.title && (target.title = title);
             return target;
         };
 
diff --git a/src/server/youtubeApi/youtubeApiSample.js b/src/server/youtubeApi/youtubeApiSample.js
index cf41a33e7..4fede08aa 100644
--- a/src/server/youtubeApi/youtubeApiSample.js
+++ b/src/server/youtubeApi/youtubeApiSample.js
@@ -23,8 +23,6 @@ module.exports.readApiKey = (callback) => {
 
 module.exports.authorizedGetChannel = (apiKey) => {
     //this didnt get called
-    console.log("I get called   ", apiKey);
-    console.log(TOKEN_PATH);
     // Authorize a client with the loaded credentials, then call the YouTube API.
     authorize(JSON.parse(apiKey), getChannel);
 }
@@ -157,7 +155,6 @@ function getSampleVideos(auth, args) {
             return;
         }
         let videos = response.data.items;
-        console.log('Videos found: ' + videos[0].id.videoId, " ", unescape(videos[0].snippet.title));
         args.callBack(videos);
     });
 }
@@ -174,7 +171,6 @@ function getVideoDetails(auth, args) {
             return;
         }
         let videoDetails = response.data.items;
-        console.log('Video Details founds: ', videoDetails);
         args.callBack(videoDetails);
     });
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 778286579008b57a76fbf82235348b613f5c1a5b Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Tue, 23 Jul 2019 18:56:23 -0400
Subject: Fixed document

---
 src/client/apis/youtube/YoutubeBox.tsx    | 24 ++----------------------
 src/server/youtubeApi/youtubeApiSample.js |  2 +-
 2 files changed, 3 insertions(+), 23 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index e630c11ae..d2f5112c2 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -81,26 +81,6 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
                 index = index + 1;
                 let newTemplate: VideoTemplate = { videoId: id, videoTitle: videoTitle, thumbnailUrl: thumbnailUrl, publishDate: pusblishDate, channelTitle: channelTitle, videoDescription: videoDescription, duration: duration!, viewCount: viewCount! };
                 runInAction(() => this.curVideoTemplates.push(newTemplate));
-
-                // runInAction(() => this.lisOfBackUp.push((
-                //     <li onClick={() => this.embedVideoOnClick(id, videoTitle)} key={Utils.GenerateGuid() + id}>
-                //         <div className="search_wrapper">
-                //             <div style={{ backgroundColor: "yellow" }}>
-                //                 <img src={thumbnailUrl} />
-                //                 <span className="video_duration">{duration}</span>
-                //             </div>
-                //             <div className="textual_info">
-                //                 <span className="videoTitle">{videoTitle}</span>
-                //                 <span className="channelName">{channelTitle}</span>
-                //                 <span className="viewCount">{viewCount}</span>
-                //                 <span className="publish_time">{pusblishDate}</span>
-                //                 <p className="video_description">{videoDescription}</p>
-
-                //             </div>
-                //         </div>
-                //     </li>)
-                // ));
-
             }
         }
     }
@@ -146,6 +126,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
                     this.videoIds = this.videoIds! + ", " + video.id.videoId;
                 }
             });
+            console.log("Video Ids: ", this.videoIds);
             DocServer.getYoutubeVideoDetails(this.videoIds, this.processVideoDetails);
             this.backUpSearchResults(videos);
             if (this.videoClicked) {
@@ -289,8 +270,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
                             duration = this.convertIsoTimeToDuration(this.videoDetails[index].contentDetails.duration);
                             viewCount = this.abbreviateViewCount(this.videoDetails[index].statistics.viewCount);
                         }
-                        //this.roundPublishTime(pusblishDate);
-                        //this.roundPublishTime2(video.snippet.publishedAt);
+
 
                         return <li onClick={() => this.embedVideoOnClick(video.id.videoId, filteredTitle)} key={Utils.GenerateGuid()}>
                             <div className="search_wrapper">
diff --git a/src/server/youtubeApi/youtubeApiSample.js b/src/server/youtubeApi/youtubeApiSample.js
index 4fede08aa..f81f0dfb5 100644
--- a/src/server/youtubeApi/youtubeApiSample.js
+++ b/src/server/youtubeApi/youtubeApiSample.js
@@ -167,7 +167,7 @@ function getVideoDetails(auth, args) {
         id: args.videoIds
     }, function (err, response) {
         if (err) {
-            console.log('The API returned an error: ' + err);
+            console.log('The API returned an error from details: ' + err);
             return;
         }
         let videoDetails = response.data.items;
-- 
cgit v1.2.3-70-g09d2


From c86f580191ddf70a6ac2994819a4f33731d79011 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Tue, 23 Jul 2019 19:07:59 -0400
Subject: Documentation

---
 src/client/apis/youtube/YoutubeBox.tsx | 87 +++++++++++++++++++---------------
 1 file changed, 50 insertions(+), 37 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index d2f5112c2..414abcc15 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -27,6 +27,9 @@ interface VideoTemplate {
     videoDescription: string;
 }
 
+/**
+ * This class models the youtube search document that can be dropped on to canvas.
+ */
 @observer
 export class YoutubeBox extends React.Component<FieldViewProps> {
 
@@ -43,6 +46,10 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
 
     public static LayoutString() { return FieldView.LayoutString(YoutubeBox); }
 
+    /**
+     * When component mounts, last search's results are laoded in based on the back up stored
+     * in the document of the props.
+     */
     async componentWillMount() {
         //DocServer.getYoutubeChannels();
         let castedSearchBackUp = Cast(this.props.Document.cachedSearchResults, Doc);
@@ -58,6 +65,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         if (jsonList!.length !== 0) {
             runInAction(() => this.searchResultsFound = true);
             let index = 0;
+            //getting the necessary information from backUps and building templates that will be used to map in render
             for (let video of jsonList!) {
 
                 let videoId = await Cast(video.id, Doc);
@@ -68,7 +76,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
                 let thumbnailMedium = await Cast(thumbnail!.medium, Doc);
                 let thumbnailUrl = StrCast(thumbnailMedium!.url);
                 let videoDescription = StrCast(snippet!.description);
-                let pusblishDate = (this.roundPublishTime2(StrCast(snippet!.publishedAt)))!;
+                let pusblishDate = (this.roundPublishTime(StrCast(snippet!.publishedAt)))!;
                 let channelTitle = StrCast(snippet!.channelTitle);
                 let duration: string;
                 let viewCount: string;
@@ -103,6 +111,9 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         }
     }
 
+    /**
+     * Function that submits the title entered by user on enter press.
+     */
     onEnterKeyDown = (e: React.KeyboardEvent) => {
         if (e.keyCode === 13) {
             let submittedTitle = this.YoutubeSearchElement!.value;
@@ -113,6 +124,11 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         }
     }
 
+    /**
+     * The callback that is passed in to server, which functions as a way to
+     * get videos that is returned by search. It also makes a call to server
+     * to get details for the videos found.
+     */
     @action
     processesVideoResults = (videos: any[]) => {
         this.searchResults = videos;
@@ -126,7 +142,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
                     this.videoIds = this.videoIds! + ", " + video.id.videoId;
                 }
             });
-            console.log("Video Ids: ", this.videoIds);
+            //Asking for details that include duration and viewCount from server for videoIds
             DocServer.getYoutubeVideoDetails(this.videoIds, this.processVideoDetails);
             this.backUpSearchResults(videos);
             if (this.videoClicked) {
@@ -135,25 +151,26 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         }
     }
 
+    /**
+     * The callback that is given to server to process and receive returned details about the videos.
+     */
     @action
     processVideoDetails = (videoDetails: any[]) => {
         this.videoDetails = videoDetails;
         this.props.Document.cachedDetails = Docs.Get.DocumentHierarchyFromJson(videoDetails, "detailBackUp");
     }
 
+    /**
+     * The function that stores the search results in the props document.
+     */
     backUpSearchResults = (videos: any[]) => {
         this.props.Document.cachedSearchResults = Docs.Get.DocumentHierarchyFromJson(videos, "videosBackUp");
-        let newCachedList = new List<Doc>();
-        this.props.Document.cachedSearch = newCachedList;
-        videos.forEach((video) => {
-            let videoBackUp = new Doc();
-            videoBackUp.videoId = video.id.videoId;
-            videoBackUp.videoTitle = this.filterYoutubeTitleResult(video.snippet.title);
-            videoBackUp.thumbnailUrl = video.snippet.thumbnails.medium.url;
-            newCachedList.push(videoBackUp);
-        });
     }
 
+    /**
+     * The function that filters out escaped characters returned by the api
+     * in the title of the videos.
+     */
     filterYoutubeTitleResult = (resultTitle: string) => {
         let processedTitle: string = resultTitle.ReplaceAll("&amp;", "&");
         processedTitle = processedTitle.ReplaceAll("&#39;", "'");
@@ -161,32 +178,13 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         return processedTitle;
     }
 
-    roundPublishTime = (publishTime: string) => {
-        let date = new Date(publishTime);
-        let curDate = new Date();
-        let videoYearDif = curDate.getFullYear() - date.getFullYear();
-        let videoMonthDif = curDate.getMonth() - date.getMonth();
-        let videoDayDif = curDate.getDay() - date.getDay();
-        let videoHoursDif = curDate.getHours() - date.getHours();
-        let videoMinutesDif = curDate.getMinutes() - date.getMinutes();
-        let videoSecondsDif = curDate.getSeconds() - date.getSeconds();
-        if (videoYearDif !== 0) {
-            return videoYearDif + " years ago";
-        } else if (videoMonthDif !== 0) {
-            return videoMonthDif + " months ago";
-        } else if (videoDayDif !== 0) {
-            return videoDayDif + " days ago";
-        } else if (videoHoursDif !== 0) {
-            return videoHoursDif + " hours ago";
-        } else if (videoMinutesDif) {
-            return videoMinutesDif + " minutes ago";
-        } else if (videoSecondsDif) {
-            return videoSecondsDif + " seconds ago";
-        }
 
-    }
 
-    roundPublishTime2 = (publishTime: string) => {
+    /**
+     * The function that converts ISO date, which is passed in, to normal date and finds the
+     * difference between today's date and that date, in terms of "ago" to imitate youtube.
+     */
+    roundPublishTime = (publishTime: string) => {
         let date = new Date(publishTime).getTime();
         let curDate = new Date().getTime();
         let timeDif = curDate - date;
@@ -228,6 +226,9 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         }
     }
 
+    /**
+     * The function that converts the passed in ISO time to normal duration time.
+     */
     convertIsoTimeToDuration = (isoDur: string) => {
 
         let convertedTime = isoDur.replace(/D|H|M/g, ":").replace(/P|T|S/g, "").split(":");
@@ -243,6 +244,10 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         return convertedTime.join(":");
     }
 
+    /**
+     * The function that rounds the viewCount to the nearest 
+     * thousand, million or billion, given a viewCount number.
+     */
     abbreviateViewCount = (viewCount: number) => {
         if (viewCount < 1000) {
             return viewCount.toString();
@@ -255,6 +260,11 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         }
     }
 
+    /**
+     * The function that is called to decide on what'll be rendered by the component.
+     * It renders search Results if found. If user didn't do a new search, it renders from the videoTemplates
+     * generated by the backUps. If none present, renders nothing.
+     */
     renderSearchResultsOrVideo = () => {
         if (this.searchResultsFound) {
             if (this.searchResults.length !== 0) {
@@ -263,7 +273,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
                         let filteredTitle = this.filterYoutubeTitleResult(video.snippet.title);
                         let channelTitle = video.snippet.channelTitle;
                         let videoDescription = video.snippet.description;
-                        let pusblishDate = this.roundPublishTime2(video.snippet.publishedAt);
+                        let pusblishDate = this.roundPublishTime(video.snippet.publishedAt);
                         let duration;
                         let viewCount;
                         if (this.videoDetails.length !== 0) {
@@ -316,6 +326,10 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         }
     }
 
+    /**
+     * Given a videoId and title, creates a new youtube embedded url, and uses that
+     * to create a new video document.
+     */
     @action
     embedVideoOnClick = (videoId: string, filteredTitle: string) => {
         let embeddedUrl = "https://www.youtube.com/embed/" + videoId;
@@ -329,7 +343,6 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
     }
 
     render() {
-        let field = this.props.Document[this.props.fieldKey];
         let content =
             <div style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
                 <input type="text" placeholder="Search for a video" onKeyDown={this.onEnterKeyDown} style={{ height: 40, width: "100%", border: "1px solid black", padding: 5, textAlign: "center" }} ref={(e) => this.YoutubeSearchElement = e!} />
-- 
cgit v1.2.3-70-g09d2


From 6cdebe507b777f60a0e30a1d7a75300304fbce09 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Tue, 23 Jul 2019 19:17:03 -0400
Subject: Refactor and flag

---
 src/client/apis/youtube/YoutubeBox.tsx    | 63 ++++++++++++++++---------------
 src/server/youtubeApi/youtubeApiSample.js |  4 +-
 2 files changed, 35 insertions(+), 32 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 414abcc15..8d6334c6e 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -58,37 +58,40 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
         let awaitedDetails = await castedDetailBackUp;
 
 
-
-        let jsonList = await DocListCastAsync(awaitedBackUp!.json);
-        let jsonDetailList = await DocListCastAsync(awaitedDetails!.json);
-
-        if (jsonList!.length !== 0) {
-            runInAction(() => this.searchResultsFound = true);
-            let index = 0;
-            //getting the necessary information from backUps and building templates that will be used to map in render
-            for (let video of jsonList!) {
-
-                let videoId = await Cast(video.id, Doc);
-                let id = StrCast(videoId!.videoId);
-                let snippet = await Cast(video.snippet, Doc);
-                let videoTitle = this.filterYoutubeTitleResult(StrCast(snippet!.title));
-                let thumbnail = await Cast(snippet!.thumbnails, Doc);
-                let thumbnailMedium = await Cast(thumbnail!.medium, Doc);
-                let thumbnailUrl = StrCast(thumbnailMedium!.url);
-                let videoDescription = StrCast(snippet!.description);
-                let pusblishDate = (this.roundPublishTime(StrCast(snippet!.publishedAt)))!;
-                let channelTitle = StrCast(snippet!.channelTitle);
-                let duration: string;
-                let viewCount: string;
-                if (jsonDetailList!.length !== 0) {
-                    let contentDetails = await Cast(jsonDetailList![index].contentDetails, Doc);
-                    let statistics = await Cast(jsonDetailList![index].statistics, Doc);
-                    duration = this.convertIsoTimeToDuration(StrCast(contentDetails!.duration));
-                    viewCount = this.abbreviateViewCount(NumCast(statistics!.viewCount))!;
+        if (awaitedBackUp) {
+
+
+            let jsonList = await DocListCastAsync(awaitedBackUp!.json);
+            let jsonDetailList = await DocListCastAsync(awaitedDetails!.json);
+
+            if (jsonList!.length !== 0) {
+                runInAction(() => this.searchResultsFound = true);
+                let index = 0;
+                //getting the necessary information from backUps and building templates that will be used to map in render
+                for (let video of jsonList!) {
+
+                    let videoId = await Cast(video.id, Doc);
+                    let id = StrCast(videoId!.videoId);
+                    let snippet = await Cast(video.snippet, Doc);
+                    let videoTitle = this.filterYoutubeTitleResult(StrCast(snippet!.title));
+                    let thumbnail = await Cast(snippet!.thumbnails, Doc);
+                    let thumbnailMedium = await Cast(thumbnail!.medium, Doc);
+                    let thumbnailUrl = StrCast(thumbnailMedium!.url);
+                    let videoDescription = StrCast(snippet!.description);
+                    let pusblishDate = (this.roundPublishTime(StrCast(snippet!.publishedAt)))!;
+                    let channelTitle = StrCast(snippet!.channelTitle);
+                    let duration: string;
+                    let viewCount: string;
+                    if (jsonDetailList!.length !== 0) {
+                        let contentDetails = await Cast(jsonDetailList![index].contentDetails, Doc);
+                        let statistics = await Cast(jsonDetailList![index].statistics, Doc);
+                        duration = this.convertIsoTimeToDuration(StrCast(contentDetails!.duration));
+                        viewCount = this.abbreviateViewCount(NumCast(statistics!.viewCount))!;
+                    }
+                    index = index + 1;
+                    let newTemplate: VideoTemplate = { videoId: id, videoTitle: videoTitle, thumbnailUrl: thumbnailUrl, publishDate: pusblishDate, channelTitle: channelTitle, videoDescription: videoDescription, duration: duration!, viewCount: viewCount! };
+                    runInAction(() => this.curVideoTemplates.push(newTemplate));
                 }
-                index = index + 1;
-                let newTemplate: VideoTemplate = { videoId: id, videoTitle: videoTitle, thumbnailUrl: thumbnailUrl, publishDate: pusblishDate, channelTitle: channelTitle, videoDescription: videoDescription, duration: duration!, viewCount: viewCount! };
-                runInAction(() => this.curVideoTemplates.push(newTemplate));
             }
         }
     }
diff --git a/src/server/youtubeApi/youtubeApiSample.js b/src/server/youtubeApi/youtubeApiSample.js
index f81f0dfb5..9853241b6 100644
--- a/src/server/youtubeApi/youtubeApiSample.js
+++ b/src/server/youtubeApi/youtubeApiSample.js
@@ -28,7 +28,7 @@ module.exports.authorizedGetChannel = (apiKey) => {
 }
 
 module.exports.authorizedGetVideos = (apiKey, userInput, callBack) => {
-    authorize(JSON.parse(apiKey), getSampleVideos, { userInput: userInput, callBack: callBack });
+    authorize(JSON.parse(apiKey), getVideos, { userInput: userInput, callBack: callBack });
 }
 
 module.exports.authorizedGetVideoDetails = (apiKey, videoIds, callBack) => {
@@ -141,7 +141,7 @@ function getChannel(auth) {
     });
 }
 
-function getSampleVideos(auth, args) {
+function getVideos(auth, args) {
     let service = google.youtube('v3');
     service.search.list({
         auth: auth,
-- 
cgit v1.2.3-70-g09d2


From f5b17bf655ab93d3214ebd1eb7697dd21265d3b5 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Tue, 23 Jul 2019 19:27:25 -0400
Subject: Casting problem fixed

---
 src/client/apis/youtube/YoutubeBox.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 8d6334c6e..019d191bc 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -86,7 +86,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
                         let contentDetails = await Cast(jsonDetailList![index].contentDetails, Doc);
                         let statistics = await Cast(jsonDetailList![index].statistics, Doc);
                         duration = this.convertIsoTimeToDuration(StrCast(contentDetails!.duration));
-                        viewCount = this.abbreviateViewCount(NumCast(statistics!.viewCount))!;
+                        viewCount = this.abbreviateViewCount(parseInt(StrCast(statistics!.viewCount)))!;
                     }
                     index = index + 1;
                     let newTemplate: VideoTemplate = { videoId: id, videoTitle: videoTitle, thumbnailUrl: thumbnailUrl, publishDate: pusblishDate, channelTitle: channelTitle, videoDescription: videoDescription, duration: duration!, viewCount: viewCount! };
-- 
cgit v1.2.3-70-g09d2


From 5b455e2aaf119c7db1fe9ef22d71a3accf55a8e2 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 30 Jul 2019 10:27:42 -0400
Subject: tweaks.

---
 src/client/apis/youtube/YoutubeBox.tsx             | 22 +++++++++-------------
 src/client/views/collections/CollectionView.tsx    |  2 +-
 .../views/collections/CollectionViewChromes.tsx    |  1 +
 3 files changed, 11 insertions(+), 14 deletions(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 019d191bc..7f9a3ad70 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -1,20 +1,16 @@
-import "../../views/nodes/WebBox.scss";
-import React = require("react");
-import { FieldViewProps, FieldView } from "../../views/nodes/FieldView";
-import { HtmlField } from "../../../new_fields/HtmlField";
-import { WebField } from "../../../new_fields/URLField";
+import { action, observable, runInAction } from 'mobx';
 import { observer } from "mobx-react";
-import { computed, reaction, IReactionDisposer, observable, action, runInAction } from 'mobx';
-import { DocumentDecorations } from "../../views/DocumentDecorations";
-import { InkingControl } from "../../views/InkingControl";
+import { Doc, DocListCastAsync } from "../../../new_fields/Doc";
+import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
-import { NumCast, Cast, StrCast } from "../../../new_fields/Types";
-import "./YoutubeBox.scss";
 import { Docs } from "../../documents/Documents";
-import { Doc, DocListCastAsync } from "../../../new_fields/Doc";
-import { listSpec } from "../../../new_fields/Schema";
-import { List } from "../../../new_fields/List";
+import { DocumentDecorations } from "../../views/DocumentDecorations";
+import { InkingControl } from "../../views/InkingControl";
+import { FieldView, FieldViewProps } from "../../views/nodes/FieldView";
+import "../../views/nodes/WebBox.scss";
+import "./YoutubeBox.scss";
+import React = require("react");
 
 interface VideoTemplate {
     thumbnailUrl: string;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index b7ac8768f..212cc5477 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -85,7 +85,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
         }
         else {
             return [
-                (<CollectionViewBaseChrome CollectionView={this} type={type} collapse={this.collapse} />),
+                (<CollectionViewBaseChrome CollectionView={this} key="chrome" type={type} collapse={this.collapse} />),
                 this.SubViewHelper(type, renderProps)
             ];
         }
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 2bffe3cc0..38aafd3cc 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -208,6 +208,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                             <input className="collectionViewBaseChrome-viewSpecsInput"
                                 placeholder="FILTER DOCUMENTS"
                                 value={this.filterValue ? this.filterValue.script.originalScript : ""}
+                                onChange={(e) => { }}
                                 onPointerDown={this.openViewSpecs} />
                             <div className="collectionViewBaseChrome-viewSpecsMenu"
                                 onPointerDown={this.openViewSpecs}
-- 
cgit v1.2.3-70-g09d2


From 2b25d87366efe167091f329c6e57d6fe1d9de7af Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Tue, 30 Jul 2019 16:44:54 -0400
Subject: oops styling fixeS

---
 src/client/apis/youtube/YoutubeBox.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/apis/youtube/YoutubeBox.tsx')

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 7f9a3ad70..dc142802c 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -343,7 +343,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
 
     render() {
         let content =
-            <div style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
+            <div className="youtubeBox-cont" style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
                 <input type="text" placeholder="Search for a video" onKeyDown={this.onEnterKeyDown} style={{ height: 40, width: "100%", border: "1px solid black", padding: 5, textAlign: "center" }} ref={(e) => this.YoutubeSearchElement = e!} />
                 {this.renderSearchResultsOrVideo()}
             </div>;
-- 
cgit v1.2.3-70-g09d2

