Skip to content

Commit d0d92ac

Browse files
committed
refactor, sort files, import from jsfiddle and plunker
1 parent b91d7fa commit d0d92ac

17 files changed

+218
-102
lines changed

src/editing/edit-session-factory.js

+11-5
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,24 @@ import {EventAggregator} from 'aurelia-event-aggregator';
33
import {GistAdapter} from './gist-adapter';
44
import {WorkerClient} from '../worker/worker-client';
55
import {EditSession} from './edit-session';
6+
import {QueryString} from './query-string';
67

7-
@inject(EventAggregator, WorkerClient, GistAdapter)
8+
@inject(EventAggregator, WorkerClient, GistAdapter, QueryString)
89
export class EditSessionFactory {
9-
constructor(eventAggregator, worker, gistAdapter) {
10+
constructor(eventAggregator, worker, gistAdapter, queryString) {
1011
this.eventAggregator = eventAggregator;
1112
this.worker = worker;
1213
this.gistAdapter = gistAdapter;
14+
this.queryString = queryString;
1315
}
1416

1517
create(gist) {
16-
let editSesson = new EditSession(gist, this.eventAggregator, this.worker, this.gistAdapter);
17-
return editSesson.resetWorker()
18-
.then(() => editSesson);
18+
let editSesson = new EditSession(
19+
gist,
20+
this.eventAggregator,
21+
this.worker,
22+
this.gistAdapter,
23+
this.queryString);
24+
return editSesson.resetWorker().then(() => editSesson);
1925
}
2026
}

src/editing/edit-session.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
import {computedFrom} from 'aurelia-framework';
22
import {RunEvent} from './run-event';
33
import {CurrentFileChangedEvent} from './current-file-changed-event';
4-
import {getEditorMode} from './editor-mode';
54
import {File} from './file';
5+
import {stringComparisonOrdinalIgnoreCase} from '../util';
66

77
export class EditSession {
8-
constructor(gist, eventAggregator, worker, gistAdapter) {
8+
constructor(gist, eventAggregator, worker, gistAdapter, queryString) {
99
this.gist = gist;
1010
this.eventAggregator = eventAggregator;
1111
this.worker = worker;
1212
this.gistAdapter = gistAdapter;
13+
this.queryString = queryString;
1314
this.autoRun = true;
1415
this.files = gistAdapter.filesMapToArray(gist.files);
16+
this.sortFiles();
1517
this._currentFile = this.files[0];
1618
}
1719

20+
sortFiles() {
21+
this.files.sort((a, b) => stringComparisonOrdinalIgnoreCase(a.name, b.name));
22+
}
23+
1824
_currentFile = null;
1925
@computedFrom('_currentFile')
2026
get currentFile() {
@@ -58,6 +64,7 @@ export class EditSession {
5864
renameFile(file, name) {
5965
this.worker.deleteFile(file.clone())
6066
.then(() => file.rename(name))
67+
.then(() => this.sortFiles())
6168
.then(() => this.worker.updateFile(file.clone()))
6269
.then(::this.run);
6370
}
@@ -93,6 +100,7 @@ export class EditSession {
93100
.then(gist => {
94101
this.gist = gist;
95102
this.files = this.gistAdapter.filesMapToArray(gist.files);
103+
this.queryString.write(gist, false);
96104
return this.resetWorker();
97105
})
98106
.then(() => this.currentFile = this.files.find(f => f.name === selected) || this.files[0]);

src/editing/gist-adapter.js

+7-20
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,13 @@ export class GistAdapter {
2727

2828
filesMapToArray(filesMap) {
2929
let files = [];
30-
for (name in filesMap) {
30+
for (let name in filesMap) {
3131
let gistFile = filesMap[name];
3232
let file = new File(toUrl(name), gistFile.type, gistFile.content);
33-
if (file.name === 'index.html') {
34-
files.unshift(file);
35-
} else {
36-
files.push(file);
37-
}
33+
files.push(file);
3834
}
3935
if (files.findIndex(f => f.name === 'index.html')) {
40-
files.unshift(new File('index.html', 'text/html', defaultIndexHtml));
36+
files.push(new File('index.html', 'text/html', defaultIndexHtml));
4137
}
4238
return files;
4339
}
@@ -55,7 +51,7 @@ export class GistAdapter {
5551
getUpdateFiles(filesMap, filesArray) {
5652
let files = filesArray.slice(0);
5753
let map = {};
58-
for (name in filesMap) {
54+
for (let name in filesMap) {
5955
let index = files.findIndex(f => f.originalName === name);
6056
let filename = toFilename(name);
6157
if (index === -1) {
@@ -104,29 +100,20 @@ export class GistAdapter {
104100

105101
save(gist, filesArray, forceFork, secret) {
106102
let files;
107-
let promise;
108103
let description = gist.description;
109104
switch (this.getSaveAction(gist, forceFork)) {
110105
case saveAction.update:
111106
files = this.getUpdateFiles(gist.files, filesArray);
112-
promise = this.gists.update(gist.id, { description, files });
113-
break;
107+
return this.gists.update(gist.id, { description, files });
114108
case saveAction.fork:
115-
promise = this.gists.fork(gist.id)
109+
return this.gists.fork(gist.id)
116110
.then(gist => {
117111
files = this.getUpdateFiles(gist.files, filesArray);
118112
return this.gists.update(gist.id, { public: !secret, description, files });
119113
});
120-
break;
121114
case saveAction.create:
122115
files = this.getCreateFiles(filesArray);
123-
promise = this.gists.create({ public: !secret, description, files });
124-
break;
116+
return this.gists.create({ public: !secret, description, files });
125117
}
126-
127-
return promise.then(gist => {
128-
history.pushState(null, window.title, '?' + this.gists.toQuery(gist, false));
129-
return gist;
130-
});
131118
}
132119
}

src/editing/query-string.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import {inject} from 'aurelia-framework';
2+
import {param, deparam} from '../util';
3+
import {Gists} from '../github/gists';
4+
import {defaultGist} from '../github/default-gist';
5+
6+
@inject(Gists)
7+
export class QueryString {
8+
constructor(gists) {
9+
this.gists = gists;
10+
}
11+
12+
clear() {
13+
history.replaceState(null, document.title, '/');
14+
}
15+
16+
read() {
17+
let query = location.search;
18+
if (query.length) {
19+
let args = deparam(query.substring(1));
20+
if (args.id) {
21+
return this.gists.load(args.id, args.sha).catch(reason => {
22+
this.clear();
23+
return defaultGist;
24+
});
25+
} else {
26+
this.clear();
27+
}
28+
}
29+
return Promise.resolve(defaultGist);
30+
}
31+
32+
write(gist, withSha) {
33+
if (!gist.id || !gist.history) {
34+
this.clear();
35+
return;
36+
}
37+
let query;
38+
if (withSha) {
39+
query = param({ id: gist.id, sha: gist.history[0].version });
40+
} else {
41+
query = param({ id: gist.id });
42+
}
43+
history.pushState(null, window.title, '?' + query);
44+
}
45+
}

src/github/gists.js

-17
Original file line numberDiff line numberDiff line change
@@ -73,21 +73,4 @@ export class Gists {
7373
})
7474
.then(fork => this.load(fork.id));
7575
}
76-
77-
fromQuery(query) {
78-
if (query.length) {
79-
let args = deparam(query.substring(1));
80-
if (args.id) {
81-
return this.load(args.id, args.sha);
82-
}
83-
}
84-
return new Promise(resolve => resolve(null));
85-
}
86-
87-
toQuery(gist, withSha) {
88-
if (withSha) {
89-
return param({ id: gist.id, sha: gist.history[0].version });
90-
}
91-
return param({ id: gist.id });
92-
}
9376
}

src/github/user.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export class User {
1111
this.accessToken = accessToken;
1212
this.api = api;
1313
this.oauth = oauth;
14-
this.setAnonymous();
14+
this.load();
1515
}
1616

1717
setAnonymous() {

src/import/gist.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {inject} from 'aurelia-framework';
2+
import {Gists} from '../github/gists';
3+
4+
const gistUrlRegex = /(?:^|\/)([\da-f]{20})(?:\/([\da-f]{40})){0,1}$/;
5+
6+
@inject(Gists)
7+
export class GistImporter {
8+
constructor(gists) {
9+
this.gists = gists;
10+
}
11+
12+
canImport(urlOrId) {
13+
return gistUrlRegex.test(urlOrId);
14+
}
15+
16+
import(urlOrId) {
17+
let match = gistUrlRegex.exec(urlOrId);
18+
let id = match[1];
19+
let sha = match[2];
20+
21+
return this.gists.load(id, sha);
22+
}
23+
}

src/import/importer.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {inject} from 'aurelia-framework';
2+
import {GistImporter} from './gist';
3+
import {JSFiddleImporter} from './jsfiddle';
4+
import {PlunkerImporter} from './plunker';
5+
6+
@inject(GistImporter, JSFiddleImporter, PlunkerImporter)
7+
export class Importer {
8+
constructor(...importers) {
9+
this.importers = importers;
10+
}
11+
12+
import(urlOrId) {
13+
let importer = this.importers.find(x => x.canImport(urlOrId));
14+
if (importer) {
15+
return importer.import(urlOrId);
16+
}
17+
return Promise.reject('Unrecognized URL or ID');
18+
}
19+
}

src/import/jsfiddle.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
export class JSFiddleImporter {
2+
fiddleHtmlToGist(page) {
3+
let div = document.createElement('div');
4+
div.innerHTML = /<input id="id_title".*\/>/.exec(page)[0]
5+
let title = div.firstElementChild.value;
6+
div.innerHTML = /<textarea id="id_description".*<\/textarea>/.exec(page)[0];
7+
let description = div.firstElementChild.value;
8+
div.innerHTML = /<fieldset class="column left">(.|\n)*<\/fieldset>/.exec(page)[0];
9+
let html = div.querySelector('#id_code_html').value;
10+
let css = div.querySelector('#id_code_css').value;
11+
let js = div.querySelector('#id_code_js').value;
12+
13+
// todo: external resources and frameworks...
14+
15+
return {
16+
description: title + ' - ' + description,
17+
files: {
18+
'index.html': {
19+
type: 'text/html',
20+
content: `<!doctype html>\n<html lang="en">\n<head>\n <meta charset="utf-8">\n <title>GistRun</title>\n <link rel="stylesheet" href="styles.css">\n</head>\n<body>\n${html}\n <script src="script.js"></script>\n</body>\n</html>`
21+
},
22+
'script.js': {
23+
type: 'application/javascript',
24+
content: js
25+
},
26+
'styles.css': {
27+
contentType: 'text/css',
28+
content: css
29+
}
30+
}
31+
};
32+
}
33+
34+
canImport(urlOrId) {
35+
return /^https:\/\/jsfiddle.net\/[\da-z]+(\/\d+)?\/?$/.test(urlOrId);
36+
}
37+
38+
import(urlOrId) {
39+
return fetch(`https://crossorigin.me/${urlOrId}`)
40+
.then(response => response.text())
41+
.then(page => this.fiddleHtmlToGist(page));
42+
}
43+
}

src/import/plunker.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const urlRegex = /^http:\/\/plnkr.co\/(?:edit\/)?([\da-zA-Z]{6})/;
2+
3+
export class PlunkerImporter {
4+
canImport(urlOrId) {
5+
return urlRegex.test(urlOrId);
6+
}
7+
8+
import(urlOrId) {
9+
let plunkerID = urlRegex.exec(urlOrId)[1];
10+
return fetch(`https://api.plnkr.co/plunks/${plunkerID}`)
11+
.then(response => response.json())
12+
.then(plunk => {
13+
let gist = { description: plunk.description, files: {} };
14+
for (let name in plunk.files) {
15+
gist.files[name] = { content: plunk.files[name].content };
16+
}
17+
return gist;
18+
});
19+
}
20+
}

src/ui/app.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<require from="./edit-file-panel.html"></require>
88
<require from="./result-panel"></require>
99

10-
<header load-gist.call="loadGist(urlOrId)" new-gist.call="newGist()"></header>
10+
<header import.call="import(urlOrId)" new.call="newGist()"></header>
1111

1212
<rate-alert></rate-alert>
1313

0 commit comments

Comments
 (0)