From 4d6711c883caac215b4262c8919aa44e9503f22d Mon Sep 17 00:00:00 2001 From: Tianyi Lin Date: Fri, 2 Jun 2017 16:24:16 -0700 Subject: [PATCH 1/5] add create-in-gist hook and save button --- src/components/header/index.js | 1 + src/components/header/renderer.js | 81 ++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/components/header/index.js b/src/components/header/index.js index e5e0b2f..be15a3a 100644 --- a/src/components/header/index.js +++ b/src/components/header/index.js @@ -4,6 +4,7 @@ import * as EditorActions from '../../actions/editor'; const mapStateToProps = function (state, ownProps) { return { + editorString: state.app.editorString, mode: state.app.mode }; }; diff --git a/src/components/header/renderer.js b/src/components/header/renderer.js index bf7f646..02a385f 100644 --- a/src/components/header/renderer.js +++ b/src/components/header/renderer.js @@ -16,7 +16,9 @@ export default class Header extends React.Component { super(props); this.state = { showVega: props.mode === MODES.Vega, - url: '' + url: '', + filename: '', + description: '' }; this.onSelectVega = this.onSelectVega.bind(this); } @@ -25,6 +27,14 @@ export default class Header extends React.Component { this.setState({url: event.target.value}); } + handleFilenameChange(event) { + this.setState({filename: event.target.value}); + } + + handleDesChange(event) { + this.setState({description: event.target.value}); + } + onSelectVega (name) { this.setState({ exampleIsOpened: false @@ -83,7 +93,34 @@ export default class Header extends React.Component { }) } + postData(filename, description) { + fetch('https://hook.io/tianyiii/create-in-gist/' + filename + '/' + description, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + spec: this.props.editorString, + }) + }).then((response) => { + return response.json(); + }).then((value) => { + console.log(value[filename]); + }) + } + render () { + const saveInGistButton = ( +
{ + this.setState({ + saveIsOpened: true + }); + }}> + {'Save'} +
+ ); + const examplesButton = (
{ @@ -210,6 +247,29 @@ export default class Header extends React.Component {
); + const saveGist = ( +
+
+ filename: + + + description: + + + +
+
+ ); + return (
IDL Logo @@ -217,6 +277,7 @@ export default class Header extends React.Component { {gistButton} {docsLink} {customButton} + {saveInGistButton} + { this.setState({ saveIsOpened: false});}} + > +
+
+ +
+
+
+ {saveGist} +
+
+
+
+
+ ); }; }; From 7f01ccaafe62d8be6e9fde0c9c47d2f109bc9712 Mon Sep 17 00:00:00 2001 From: Tianyi Lin Date: Fri, 2 Jun 2017 16:24:55 -0700 Subject: [PATCH 2/5] add save in gist hook --- hooks/createGist.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 hooks/createGist.js diff --git a/hooks/createGist.js b/hooks/createGist.js new file mode 100644 index 0000000..8c5cc66 --- /dev/null +++ b/hooks/createGist.js @@ -0,0 +1,28 @@ +module['exports'] = function myService (hook) { + + var github = require('octonode'); + + var filename = hook.params.filename; + var description = hook.params.description; + var spec = hook.params.spec; + + var client = github.client(); + + var files = {}; + + files[filename] = {"content": spec}; + + var ghgist = client.gist(); + + ghgist.create({ + description: description, + files: files, + public: true + }, function(err, g){ + if (err) { + return hook.res.json(err); + } + hook.res.json(g.files); + + }); +}; \ No newline at end of file From 689e288c3018e2542012c1dca4f16aaa58152b04 Mon Sep 17 00:00:00 2001 From: Tianyi Lin Date: Thu, 8 Jun 2017 01:06:46 -0700 Subject: [PATCH 3/5] add hash history for gist save & fix CSS --- src/components/header/index.css | 40 +++++++++++++++++++++++++++++++ src/components/header/renderer.js | 29 +++++++++++++--------- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/components/header/index.css b/src/components/header/index.css index 6054b0b..983a7b4 100644 --- a/src/components/header/index.css +++ b/src/components/header/index.css @@ -191,6 +191,21 @@ color: white; } +.gist-save-button:hover { + background: rgb(92, 64, 141); + color: white; +} + +.gist-save-button { + background: white; + border: 1px solid #A9A9A9; + cursor: pointer; + width: 100%; + height: 30px; + font-size: 16px; + outline: none; +} + .gist-text { margin-top: 25px; font-size: 12px; @@ -213,6 +228,31 @@ padding: 5px; } +.gist-save-input { + display: inline; + width: 100%; + resize: none; + font-size: 14px; + margin-top: 5px; + margin-bottom: 30px; + padding: 5px; +} + +.gist-filename { + display: inline; +} + +.gist-filename-text { + font-size: 12px; + font-style: italic; +} + +.gist-filename-example { + font-size: 12px; + font-style: italic; + color: rgb(6,69,173); +} + .customSubmenu { font-size: 16px; padding: 5px 10px; diff --git a/src/components/header/renderer.js b/src/components/header/renderer.js index 02a385f..ffb5dbc 100644 --- a/src/components/header/renderer.js +++ b/src/components/header/renderer.js @@ -105,7 +105,9 @@ export default class Header extends React.Component { }).then((response) => { return response.json(); }).then((value) => { - console.log(value[filename]); + let arrayNames = value[filename].raw_url.split('/'); + let id = arrayNames[4]; + hashHistory.push('/gist/' + this.props.mode +'/anonymous/' + id); }) } @@ -139,7 +141,7 @@ export default class Header extends React.Component { gistIsOpened: true }); }}> - {'Gist'} + {'Load'} ); @@ -250,21 +252,26 @@ export default class Header extends React.Component { const saveGist = (
- filename: - +
+ filename: +
+ Add .json to save as a json file. For example: + test.json +
+ - description: - + description: + -
@@ -274,9 +281,9 @@ export default class Header extends React.Component {
IDL Logo {examplesButton} + {customButton} {gistButton} {docsLink} - {customButton} {saveInGistButton} Date: Thu, 8 Jun 2017 01:19:24 -0700 Subject: [PATCH 4/5] fix wording issue --- src/components/header/renderer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/header/renderer.js b/src/components/header/renderer.js index ffb5dbc..c461d90 100644 --- a/src/components/header/renderer.js +++ b/src/components/header/renderer.js @@ -253,7 +253,7 @@ export default class Header extends React.Component {
- filename: + Enter Filename:
Add .json to save as a json file. For example: test.json @@ -261,7 +261,7 @@ export default class Header extends React.Component { - description: + Enter Description: From 664d6c6d497c164a8073cdb706a482e99e8b251d Mon Sep 17 00:00:00 2001 From: Matthew Conlen Date: Wed, 14 Jun 2017 19:53:55 -0700 Subject: [PATCH 5/5] fix gist loading --- src/actions/editor.js | 70 +++++++++++++++++++++++++------ src/components/app.js | 19 +++++++-- src/components/header/index.js | 8 ++-- src/components/header/renderer.js | 48 +-------------------- 4 files changed, 80 insertions(+), 65 deletions(-) diff --git a/src/actions/editor.js b/src/actions/editor.js index e1e3e51..bca081b 100644 --- a/src/actions/editor.js +++ b/src/actions/editor.js @@ -9,6 +9,7 @@ export const TOGGLE_AUTO_PARSE = 'TOGGLE_AUTO_PARSE'; export const CYCLE_RENDERER = 'CYCLE_RENDERER'; export const SHOW_COMPILED_VEGA_SPEC = 'SHOW_COMPILED_VEGA_SPEC' export const SET_MODE = 'SET_MODE' +import { hashHistory } from 'react-router'; export function setMode (mode) { return { @@ -54,22 +55,67 @@ export function updateVegaLiteSpec (spec) { }; }; -export function setGistVegaSpec (gist, spec) { - return { - type: SET_GIST_VEGA_SPEC, - gist: gist, - spec: spec - }; -}; +const getSpecFromGistURL = (gistUrl, mode, cb) => { + let prefix = 'https://hook.io/tianyiii/vegaeditor/'; + let hookUrl = prefix + mode + '/' + + gistUrl.substring(gistUrl.indexOf('.com/') + '.com/'.length); + let suffix = hookUrl.substring(prefix.length); -export function setGistVegaLiteSpec (gist, spec) { - return { - type: SET_GIST_VEGA_LITE_SPEC, - gist: gist, - spec: spec + return fetch(hookUrl, { + method: 'get', + mode: 'cors' + }) + .then((response) => { + if (response.status === 200) { + return Promise.resolve(response); + } else { + return Promise.reject(new Error(response.statusText)); + } + }) + .then((response) => { + let arrayNames = suffix.split('/'); + if (arrayNames.length < 3) { + console.warn('invalid url'); + return; + } + let username = arrayNames[1]; + let id = arrayNames[2]; + hashHistory.push('/gist/' + mode +'/' + username + '/' + id); + return response.text(); + }) +} + +export function setGistVegaLite(url) { + return dispatch => { + getSpecFromGistURL(url, 'vega-lite') + .then((data) => { + if (data['message'] !== 'Not Found') { + dispatch({ + type: SET_GIST_VEGA_LITE_SPEC, + gist: url, + spec: data + }); + } + }); + } +} + +export function setGistVega (url) { + return dispatch => { + getSpecFromGistURL(url, 'vega') + .then((data) => { + if (data['message'] !== 'Not Found') { + dispatch({ + type: SET_GIST_VEGA_SPEC, + gist: url, + spec: data + }); + } + }); }; }; + export function toggleAutoParse () { return { type: TOGGLE_AUTO_PARSE diff --git a/src/components/app.js b/src/components/app.js index 252f7d1..6e43b63 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -41,17 +41,17 @@ class App extends React.Component { } setTimeout(() => { - this.setExample(this.props.params); + this.loadSpecFromCurrentURL(this.props.params); }, 500); } componentWillReceiveProps(nextProps) { if (this.props.params !== nextProps.params) { - this.setExample(nextProps.params); + this.loadSpecFromCurrentURL(nextProps.params); } } - setExample(parameter) { + loadSpecFromCurrentURL(parameter) { if (hashHistory.getCurrentLocation().pathname.indexOf('/edited') === -1) { if (parameter && parameter.example_name) { const name = parameter.example_name; @@ -72,6 +72,13 @@ class App extends React.Component { }); } } + } else if (parameter && parameter.username && parameter.id) { + const url = `https://gist.github.com/${parameter.username}/${parameter.id}`; + if (parameter.mode === 'vega') { + this.props.setGistVega(url); + } else { + this.props.setGistVegaLite(url); + } } } } @@ -109,6 +116,12 @@ const mapDispatchToProps = function (dispatch) { }, setVegaLiteExample: (example, val) => { dispatch(EditorActions.setVegaLiteExample(example, val)); + }, + setGistVegaLite: (url) => { + dispatch(EditorActions.setGistVegaLite(url)); + }, + setGistVega: (url) => { + dispatch(EditorActions.setGistVega(url)); } }; }; diff --git a/src/components/header/index.js b/src/components/header/index.js index be15a3a..42220cd 100644 --- a/src/components/header/index.js +++ b/src/components/header/index.js @@ -11,12 +11,12 @@ const mapStateToProps = function (state, ownProps) { const mapDispatchToProps = function (dispatch) { return { - setGistVegaSpec: (gist, spec) => { - dispatch(EditorActions.setGistVegaSpec(gist, spec)); + setGistVega: (url) => { + dispatch(EditorActions.setGistVega(url)); }, - setGistVegaLiteSpec: (gist, spec) => { - dispatch(EditorActions.setGistVegaLiteSpec(gist, spec)); + setGistVegaLite: (url) => { + dispatch(EditorActions.setGistVegaLite(url)); } }; }; diff --git a/src/components/header/renderer.js b/src/components/header/renderer.js index 89692b5..05f43ce 100644 --- a/src/components/header/renderer.js +++ b/src/components/header/renderer.js @@ -46,50 +46,6 @@ export default class Header extends React.Component { hashHistory.push('/examples/vega-lite/' + name); } - fetchData(gistUrl, vegaVersion) { - let prefix = 'https://hook.io/tianyiii/vegaeditor/'; - let hookUrl = prefix + vegaVersion + '/' - + gistUrl.substring(gistUrl.indexOf('.com/') + '.com/'.length); - let suffix = hookUrl.substring(prefix.length); - - fetch(hookUrl, { - method: 'get', - mode: 'cors' - }) - .then((response) => { - if (response.status === 200) { - return Promise.resolve(response); - } else { - return Promise.reject(new Error(response.statusText)); - } - }) - .then((response) => { - let arrayNames = suffix.split('/'); - if (arrayNames.length < 3) { - console.warn('invalid url'); - return; - } - let username = arrayNames[1]; - let id = arrayNames[2]; - hashHistory.push('/gist/' + vegaVersion +'/' + username + '/' + id); - return response.json(); - }) - .then((data) => { - if (data['message'] !== 'Not Found') { - if (vegaVersion === 'vega') { - this.props.setGistVegaSpec(hookUrl, JSON.stringify(data, null, 2)); - } else if (vegaVersion === 'vega-lite') { - this.props.setGistVegaLiteSpec(hookUrl, JSON.stringify(data, null, 2)); - } - } else { - console.warn('invalid url'); - } - }) - .catch((ex) => { - console.error(ex); - }) - } - postData(filename, description) { this.setState({ saveIsOpened: true @@ -232,7 +188,7 @@ export default class Header extends React.Component { onChange={this.handleChange.bind(this)}/>