Commit cb7c1d12 authored by Luke "Jared" Bennett's avatar Luke "Jared" Bennett

Start on components

parent 403fdf7f
/* global monaco */
import $ from 'jquery';
import Tabs from './repo_tabs';
import Sidebar from './repo_sidebar';
import Editor from './repo_editor';
import FileButtons from './repo_file_buttons';
import EditButton from './repo_edit_button';
import BinaryViewer from './repo_binary_viewer';
import CommitSection from './repo_commit_section';
import Service from './repo_service';
import Store from './repo_store';
import Helper from './repo_helper';
import monacoLoader from './monaco_loader';
function initMonaco(el, cb) {
monacoLoader(['vs/editor/editor.main'], () => {
const monacoInstance = monaco.editor.create(el, {
model: null,
readOnly: true,
contextmenu: false,
});
cb(monacoInstance);
});
}
function initRepo() {
const ide = document.getElementById('ide');
const tabs = document.getElementById('tabs');
const sidebar = document.getElementById('sidebar');
const fileButtons = document.getElementById('repo-file-buttons');
const editButton = document.getElementById('editable-mode');
const commitSection = document.getElementById('commit-area');
const binaryViewer = document.getElementById('binary-viewer');
const url = ide.dataset.url;
Store.service = Service;
Store.service.url = url;
Store.service.url = sidebar.dataset.url;
Store.tabs = new Tabs(tabs);
Store.sidebar = new Sidebar(sidebar);
Store.editor = new Editor(ide);
Store.buttons = new FileButtons(fileButtons);
Store.editButton = new EditButton(editButton);
Store.commitSection = new CommitSection(commitSection);
Store.binaryViewer = new BinaryViewer(binaryViewer);
Helper.getContent();
initMonaco(sidebar, (monacoInstance) => {
Store.monacoInstance = monacoInstance;
Store.sidebar = new Sidebar(sidebar);
Helper.getContent();
});
}
$(initRepo);
......
import Vue from 'vue';
import Store from './repo_store';
import RepoHelper from './repo_helper';
export default class RepoBinaryViewer {
constructor(el) {
this.initVue(el);
}
initVue(el) {
this.vue = new Vue({
el,
data: () => Store,
computed: {
pngBlobWithDataURI() {
return `data:image/png;base64,${this.blobRaw}`;
},
},
methods: {
isMarkdown() {
return this.activeFile.extension === 'md';
},
},
watch: {
blobRaw() {
if (this.isMarkdown()) {
this.binaryTypes.markdown = true;
this.activeFile.raw = false;
// counts as binaryish so we use the binary viewer in this case.
this.binary = true;
return;
}
if (!this.binary) return;
switch (this.binaryMimeType) {
case 'image/png':
this.binaryTypes.png = true;
break;
default:
RepoHelper.loadingError();
break;
}
},
},
});
}
}
<script>
import Vue from 'vue';
import Store from './repo_store';
import RepoHelper from './repo_helper';
const RepoBinaryViewer = {
data: () => Store,
computed: {
pngBlobWithDataURI() {
return `data:image/png;base64,${this.blobRaw}`;
},
},
methods: {
isMarkdown() {
return this.activeFile.extension === 'md';
},
},
watch: {
blobRaw() {
if (this.isMarkdown()) {
this.binaryTypes.markdown = true;
this.activeFile.raw = false;
// counts as binaryish so we use the binary viewer in this case.
this.binary = true;
return;
}
if (!this.binary) return;
switch (this.binaryMimeType) {
case 'image/png':
this.binaryTypes.png = true;
break;
default:
RepoHelper.loadingError();
break;
}
},
},
};
export default RepoBinaryViewer;
</script>
<template>
<div id="binary-viewer" v-if="binary">
<img v-if="binaryTypes.png" :src="pngBlobWithDataURI" :alt="activeFile.name"/>
<div v-if="binaryTypes.markdown" v-html="activeFile.html"></div>
</div>
</template>
/* global monaco */
import Vue from 'vue';
import Store from './repo_store';
import Helper from './repo_helper';
import monacoLoader from './monaco_loader';
export default class RepoEditor {
constructor(el) {
this.initMonaco();
Store.ideEl = el;
}
addMonacoEvents() {
this.monacoEditor.onMouseUp(RepoEditor.onMonacoEditorMouseUp);
this.monacoEditor.onKeyUp(this.onMonacoEditorKeysPressed.bind(this));
}
onMonacoEditorKeysPressed() {
Store.setActiveFileContents(this.monacoEditor.getValue());
}
initMonaco() {
monacoLoader(['vs/editor/editor.main'], () => {
this.monacoEditor = monaco.editor.create(Store.ideEl, {
model: null,
readOnly: true,
contextmenu: false,
});
Store.monacoInstance = this.monacoEditor;
this.initVue();
this.addMonacoEvents();
});
}
initVue() {
this.vue = new Vue({
data: () => Store,
created() {
this.showHide();
if (this.blobRaw === '') return;
const newModel = monaco.editor.createModel(this.blobRaw, 'plaintext');
this.monacoInstance.setModel(newModel);
},
methods: {
showHide() {
if (!this.openedFiles.length || (this.binary && !this.activeFile.raw)) {
this.ideEl.style.display = 'none';
} else {
this.ideEl.style.display = 'inline-block';
}
},
},
watch: {
activeLine() {
this.monacoInstance.setPosition({
lineNumber: this.activeLine,
column: 1,
});
},
editMode() {
const panelClassList = document.querySelector('.panel-right').classList;
let readOnly = true;
if (this.editMode) {
panelClassList.add('edit-mode');
} else {
panelClassList.remove('edit-mode');
readOnly = true;
}
this.monacoInstance.updateOptions({
readOnly,
});
},
activeFileLabel() {
this.showHide();
},
isTree() {
this.showHide();
},
openedFiles() {
this.showHide();
},
binary() {
this.showHide();
},
blobRaw() {
this.showHide();
if (this.isTree) return;
this.monacoInstance.setModel(null);
const languages = monaco.languages.getLanguages();
const languageID = Helper.getLanguageIDForFile(this.activeFile, languages);
const newModel = monaco.editor.createModel(this.blobRaw, languageID);
this.monacoInstance.setModel(newModel);
},
},
});
}
static onMonacoEditorMouseUp(e) {
if (e.target.element.className === 'line-numbers') {
location.hash = `L${e.target.position.lineNumber}`;
Store.activeLine = e.target.position.lineNumber;
}
}
}
<script>
/* global monaco */
import Vue from 'vue';
import Store from './repo_store';
import Helper from './repo_helper';
const RepoEditor = {
data: () => Store,
mounted() {
this.addMonacoEvents();
this.showHide();
if (this.blobRaw === '') return;
const newModel = monaco.editor.createModel(this.blobRaw, 'plaintext');
this.monacoInstance.setModel(newModel);
},
methods: {
showHide() {
if (!this.openedFiles.length || (this.binary && !this.activeFile.raw)) {
this.$el.style.display = 'none';
} else {
this.$el.style.display = 'inline-block';
}
},
addMonacoEvents() {
this.monacoEditor.onMouseUp(this.onMonacoEditorMouseUp);
this.monacoEditor.onKeyUp(this.onMonacoEditorKeysPressed.bind(this));
},
onMonacoEditorKeysPressed() {
Store.setActiveFileContents(this.monacoEditor.getValue());
},
onMonacoEditorMouseUp(e) {
if (e.target.element.className === 'line-numbers') {
location.hash = `L${e.target.position.lineNumber}`;
Store.activeLine = e.target.position.lineNumber;
}
}
},
watch: {
activeLine() {
this.monacoInstance.setPosition({
lineNumber: this.activeLine,
column: 1,
});
},
editMode() {
const panelClassList = document.querySelector('.panel-right').classList;
let readOnly = true;
if (this.editMode) {
panelClassList.add('edit-mode');
} else {
panelClassList.remove('edit-mode');
readOnly = true;
}
this.monacoInstance.updateOptions({
readOnly,
});
},
activeFileLabel() {
this.showHide();
},
isTree() {
this.showHide();
},
openedFiles() {
this.showHide();
},
binary() {
this.showHide();
},
blobRaw() {
this.showHide();
if (this.isTree) return;
this.monacoInstance.setModel(null);
const languages = monaco.languages.getLanguages();
const languageID = Helper.getLanguageIDForFile(this.activeFile, languages);
const newModel = monaco.editor.createModel(this.blobRaw, languageID);
this.monacoInstance.setModel(newModel);
},
},
};
export default RepoEditor;
</script>
<template>
<div id="ide"></div>
</template>
import Vue from 'vue';
import Store from './repo_store';
import Helper from './repo_helper';
import RepoMiniMixin from './repo_mini_mixin';
export default class RepoFileButtons {
constructor(el) {
this.initVue(el);
}
initVue(el) {
this.vue = new Vue({
el,
data: () => Store,
mixins: [RepoMiniMixin],
template: `
<div id='repo-file-buttons' v-if='isMini' :style='{"border-bottom": editableBorder}'>
<a :href='rawFileURL' target='_blank' class='btn btn-default'>Raw</a>
<div class="btn-group" role="group" aria-label="File actions">
<a :href='blameFileUrl' class='btn btn-default'>Blame</a>
<a :href='historyFileUrl' class='btn btn-default'>History</a>
<a href='#' class='btn btn-default'>Permalink</a>
<a href='#' class='btn btn-default'>Lock</a>
</div>
<a href='#' v-if='canPreview' @click.prevent='rawPreviewToggle' class='btn btn-default'>
{{activeFileLabel}}
</a>
<button type="button" class="btn btn-default" data-target="#modal-upload-blob" data-toggle="modal">Replace</button>
<a href='#' class='btn btn-danger'>Delete</a>
</div>
`,
computed: {
editableBorder() {
return this.editMode ? '1px solid #1F78D1' : '1px solid #f0f0f0';
},
canPreview() {
return this.activeFile.extension === 'md';
},
rawFileURL() {
return Helper.getRawURLFromBlobURL(this.activeFile.url);
},
blameFileUrl() {
return Helper.getBlameURLFromBlobURL(this.activeFile.url);
},
historyFileUrl() {
return Helper.getHistoryURLFromBlobURL(this.activeFile.url);
},
},
methods: {
rawPreviewToggle: Store.toggleRawPreview,
},
});
}
}
<script>
import Vue from 'vue';
import Store from './repo_store';
import Helper from './repo_helper';
import RepoMiniMixin from './repo_mini_mixin';
const RepoFileButtons = {
data: () => Store,
mixins: [RepoMiniMixin],
computed: {
editableBorder() {
return this.editMode ? '1px solid #1F78D1' : '1px solid #f0f0f0';
},
canPreview() {
return this.activeFile.extension === 'md';
},
rawFileURL() {
return Helper.getRawURLFromBlobURL(this.activeFile.url);
},
blameFileUrl() {
return Helper.getBlameURLFromBlobURL(this.activeFile.url);
},
historyFileUrl() {
return Helper.getHistoryURLFromBlobURL(this.activeFile.url);
},
},
methods: {
rawPreviewToggle: Store.toggleRawPreview,
},
};
export default RepoFileButtons;
</script>
<template>
<div id="repo-file-buttons" v-if="isMini" :style="{'border-bottom': editableBorder}">
<a :href="rawFileURL" target="_blank" class="btn btn-default">Raw</a>
<div class="btn-group" role="group" aria-label="File actions">
<a :href="blameFileUrl" class="btn btn-default">Blame</a>
<a :href="historyFileUrl" class="btn btn-default">History</a>
<a href="#" class="btn btn-default">Permalink</a>
<a href="#" class="btn btn-default">Lock</a>
</div>
<a href="#" v-if="canPreview" @click.prevent="rawPreviewToggle" class="btn btn-default">
{{activeFileLabel}}
</a>
<button type="button" class="btn btn-default" data-target="#modal-upload-blob" data-toggle="modal">Replace</button>
<a href="#" class="btn btn-danger">Delete</a>
</div>
</template>
......@@ -6,6 +6,10 @@ import RepoPreviousDirectory from './repo_prev_directory.vue';
import RepoFileOptions from './repo_file_options.vue';
import RepoFile from './repo_file.vue';
import RepoLoadingFile from './repo_loading_file.vue';
import RepoTabs from './repo_tabs.vue';
import RepoFileButtons from './repo_file_buttons.vue';
import RepoBinaryViewer from './repo_binary_viewer.vue';
import RepoEditor from './repo_editor.vue';
import RepoMiniMixin from './repo_mini_mixin';
export default class RepoSidebar {
......@@ -22,6 +26,10 @@ export default class RepoSidebar {
'repo-previous-directory': RepoPreviousDirectory,
'repo-file': RepoFile,
'repo-loading-file': RepoLoadingFile,
'repo-tabs': RepoTabs,
'repo-file-buttons': RepoFileButtons,
'repo-binary-viewer': RepoBinaryViewer,
'repo-editor': RepoEditor,
},
created() {
......
import Vue from 'vue';
import Store from './repo_store';
import RepoTab from './repo_tab.vue';
import RepoMiniMixin from './repo_mini_mixin';
export default class RepoTabs {
constructor(el) {
// RepoTabs.styleTabsForWindows();
this.initVue(el);
}
initVue(el) {
this.vue = new Vue({
el,
mixins: [RepoMiniMixin],
components: {
'repo-tab': RepoTab,
},
data: () => Store,
methods: {
isOverflow() {
let tabs = document.getElementById('tabs');
if(tabs) {
return tabs.scrollWidth > tabs.offsetWidth;
}
}
},
watch: {
openedFiles() {
Vue.nextTick(() => {
this.tabsOverflow = this.isOverflow();
});
}
}
});
}
// static styleTabsForWindows() {
// const scrollWidth = Number(document.body.dataset.scrollWidth);
// Store.scrollWidth = scrollWidth;
// }
}
<script>
import Vue from 'vue';
import Store from './repo_store';
import RepoTab from './repo_tab.vue';
import RepoMiniMixin from './repo_mini_mixin';
const RepoTabs = {
mixins: [RepoMiniMixin],
components: {
'repo-tab': RepoTab,
},
data: () => Store,
methods: {
isOverflow() {
return this.$el.scrollWidth > this.$el.offsetWidth;
}
},
watch: {
openedFiles() {
Vue.nextTick(() => {
this.tabsOverflow = this.isOverflow();
});
}
}
}
export default RepoTabs;
</script>
<template>
<ul id="tabs" v-if="isMini" v-cloak :class="{'overflown': tabsOverflow}">
<repo-tab v-for="tab in openedFiles" :key="tab.id" :tab="tab" :class="{'active' : tab.active}"/>
</ul>
</template>
.tree-content-holder
#sidebar{ ":class" => "{'sidebar-mini' : isMini}", "v-cloak" => "1" }<
#sidebar{ ":class" => "{'sidebar-mini' : isMini}", "v-cloak" => "1", data: { url: repo_url(@project) } }<
%table.table
%thead{ "v-if" => "!isMini" }
%th{ "v-if" => "!isMini" }
......@@ -16,13 +16,10 @@
%tr{ is: "repo-loading-file", "v-for" => "n in 5", ":loading" => "loading", ":has-files" => "!!files.length", ":is-mini" => "isMini" }
%tr{ is: "repo-file", "v-for" => "file in files", ":key" => "file.id", ":file" => "file",":is-mini" => "isMini", "@linkclicked" => "linkClicked(file)", ":is-tree" => "isTree", ":has-files" => "!!files.length", ":active-file" => "activeFile" }
.panel-right>
%ul#tabs{ "v-if" => "isMini", "v-cloak" => "1", ":class" => "{'overflown': tabsOverflow}" }
%li{ is: "repo-tab", "v-for" => "tab in openedFiles", ":key" => "tab.id", ":tab" => "tab", ":class" => "{'active' : tab.active}" }
#repo-file-buttons
#ide{ data: { url: repo_url(@project) } }
#binary-viewer{ "v-if" => "binary" }
%img{ "v-if" => "binaryTypes.png", ":src" => "pngBlobWithDataURI", ":alt" => "activeFile.name", alt: "" }
%div{ "v-if" => "binaryTypes.markdown", "v-html" => "activeFile.html" }
%repo-tabs
%repo-file-buttons
%repo-editor
%repo-binary-viewer
#commit-area{ "v-if" => "changedFiles.length" }
%form.form-horizontal
%fieldset
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment