mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
tabs wip
This commit is contained in:
parent
63ab82a076
commit
0d11cadc18
@ -149,27 +149,4 @@
|
|||||||
.chrome-tabs.chrome-tabs-is-sorting .chrome-tab:not(.chrome-tab-is-dragging),
|
.chrome-tabs.chrome-tabs-is-sorting .chrome-tab:not(.chrome-tab-is-dragging),
|
||||||
.chrome-tabs:not(.chrome-tabs-is-sorting) .chrome-tab.chrome-tab-was-just-dragged {
|
.chrome-tabs:not(.chrome-tabs-is-sorting) .chrome-tab.chrome-tab-was-just-dragged {
|
||||||
transition: transform 120ms ease-in-out;
|
transition: transform 120ms ease-in-out;
|
||||||
}
|
}
|
||||||
.chrome-tabs .chrome-tabs-bottom-bar {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
height: 4px;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
background: #fff;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
.chrome-tabs-optional-shadow-below-bottom-bar {
|
|
||||||
position: relative;
|
|
||||||
height: 1px;
|
|
||||||
width: 100%;
|
|
||||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1' viewBox='0 0 1 1'><rect x='0' y='0' width='1' height='1' fill='rgba(0, 0, 0, .17)'></rect></svg>");
|
|
||||||
background-size: 1px 1px;
|
|
||||||
background-repeat: repeat-x;
|
|
||||||
background-position: 0% 0%;
|
|
||||||
}
|
|
||||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
|
||||||
.chrome-tabs-optional-shadow-below-bottom-bar {
|
|
||||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' viewBox='0 0 2 2'><rect x='0' y='0' width='2' height='1' fill='rgba(0, 0, 0, .27)'></rect></svg>");
|
|
||||||
}
|
|
||||||
}
|
|
@ -41,12 +41,7 @@
|
|||||||
|
|
||||||
const tabTemplate = `
|
const tabTemplate = `
|
||||||
<div class="chrome-tab">
|
<div class="chrome-tab">
|
||||||
<div class="chrome-tab-dividers"></div>
|
|
||||||
<div class="chrome-tab-background">
|
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"><defs><symbol id="chrome-tab-geometry-left" viewBox="0 0 214 36"><path d="M17 0h197v36H0v-2c4.5 0 9-3.5 9-8V8c0-4.5 3.5-8 8-8z"/></symbol><symbol id="chrome-tab-geometry-right" viewBox="0 0 214 36"><use xlink:href="#chrome-tab-geometry-left"/></symbol><clipPath id="crop"><rect class="mask" width="100%" height="100%" x="0"/></clipPath></defs><svg width="52%" height="100%"><use xlink:href="#chrome-tab-geometry-left" width="214" height="36" class="chrome-tab-geometry"/></svg><g transform="scale(-1, 1)"><svg width="52%" height="100%" x="-100%" y="0"><use xlink:href="#chrome-tab-geometry-right" width="214" height="36" class="chrome-tab-geometry"/></svg></g></svg>
|
|
||||||
</div>
|
|
||||||
<div class="chrome-tab-content">
|
<div class="chrome-tab-content">
|
||||||
<div class="chrome-tab-favicon"></div>
|
|
||||||
<div class="chrome-tab-title"></div>
|
<div class="chrome-tab-title"></div>
|
||||||
<div class="chrome-tab-drag-handle"></div>
|
<div class="chrome-tab-drag-handle"></div>
|
||||||
<div class="chrome-tab-close"></div>
|
<div class="chrome-tab-close"></div>
|
||||||
@ -211,6 +206,8 @@
|
|||||||
this.cleanUpPreviouslyDraggedTabs()
|
this.cleanUpPreviouslyDraggedTabs()
|
||||||
this.layoutTabs()
|
this.layoutTabs()
|
||||||
this.setupDraggabilly()
|
this.setupDraggabilly()
|
||||||
|
|
||||||
|
return tabEl
|
||||||
}
|
}
|
||||||
|
|
||||||
setTabCloseEventListener(tabEl) {
|
setTabCloseEventListener(tabEl) {
|
||||||
@ -251,15 +248,6 @@
|
|||||||
updateTab(tabEl, tabProperties) {
|
updateTab(tabEl, tabProperties) {
|
||||||
tabEl.querySelector('.chrome-tab-title').textContent = tabProperties.title
|
tabEl.querySelector('.chrome-tab-title').textContent = tabProperties.title
|
||||||
|
|
||||||
const faviconEl = tabEl.querySelector('.chrome-tab-favicon')
|
|
||||||
if (tabProperties.favicon) {
|
|
||||||
faviconEl.style.backgroundImage = `url('${ tabProperties.favicon }')`
|
|
||||||
faviconEl.removeAttribute('hidden', '')
|
|
||||||
} else {
|
|
||||||
faviconEl.setAttribute('hidden', '')
|
|
||||||
faviconEl.removeAttribute('style')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tabProperties.id) {
|
if (tabProperties.id) {
|
||||||
tabEl.setAttribute('data-tab-id', tabProperties.id)
|
tabEl.setAttribute('data-tab-id', tabProperties.id)
|
||||||
}
|
}
|
||||||
|
@ -157,13 +157,3 @@ noteTypeService.init();
|
|||||||
linkService.init();
|
linkService.init();
|
||||||
|
|
||||||
noteAutocompleteService.init();
|
noteAutocompleteService.init();
|
||||||
|
|
||||||
$(document).ready(() => {
|
|
||||||
const el = $('.chrome-tabs')[0];
|
|
||||||
const chromeTabs = new ChromeTabs();
|
|
||||||
chromeTabs.init(el);
|
|
||||||
|
|
||||||
el.addEventListener('activeTabChange', ({detail}) => console.log('Active tab changed', detail.tabEl));
|
|
||||||
el.addEventListener('tabAdd', ({detail}) => console.log('Tab added', detail.tabEl));
|
|
||||||
el.addEventListener('tabRemove', ({detail}) => console.log('Tab removed', detail.tabEl));
|
|
||||||
});
|
|
@ -36,6 +36,9 @@ async function getAttributes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function showAttributes() {
|
async function showAttributes() {
|
||||||
|
// FIXME tabs
|
||||||
|
return;
|
||||||
|
|
||||||
$promotedAttributesContainer.empty();
|
$promotedAttributesContainer.empty();
|
||||||
$attributeList.hide();
|
$attributeList.hide();
|
||||||
$attributeListInner.empty();
|
$attributeListInner.empty();
|
||||||
|
@ -106,9 +106,9 @@ function init() {
|
|||||||
// of opening the link in new window/tab
|
// of opening the link in new window/tab
|
||||||
$(document).on('click', "a[data-action='note']", goToLink);
|
$(document).on('click', "a[data-action='note']", goToLink);
|
||||||
$(document).on('click', 'div.popover-content a, div.ui-tooltip-content a', goToLink);
|
$(document).on('click', 'div.popover-content a, div.ui-tooltip-content a', goToLink);
|
||||||
$(document).on('dblclick', '#note-detail-text a', goToLink);
|
$(document).on('dblclick', '.note-detail-text a', goToLink);
|
||||||
$(document).on('click', '#note-detail-render a', goToLink);
|
$(document).on('click', '.note-detail-render a', goToLink);
|
||||||
$(document).on('click', '#note-detail-text.ck-read-only a', goToLink);
|
$(document).on('click', '.note-detail-text.ck-read-only a', goToLink);
|
||||||
$(document).on('click', 'span.ck-button__label', e => {
|
$(document).on('click', 'span.ck-button__label', e => {
|
||||||
// this is a link preview dialog from CKEditor link editing
|
// this is a link preview dialog from CKEditor link editing
|
||||||
// for some reason clicked element is span
|
// for some reason clicked element is span
|
||||||
|
@ -13,7 +13,15 @@ import noteDetailSearch from "./note_detail_search.js";
|
|||||||
import noteDetailRender from "./note_detail_render.js";
|
import noteDetailRender from "./note_detail_render.js";
|
||||||
import noteDetailRelationMap from "./note_detail_relation_map.js";
|
import noteDetailRelationMap from "./note_detail_relation_map.js";
|
||||||
|
|
||||||
const $noteTabsContainer = $("#note-tab-container");
|
const $noteTabContentsContainer = $("#note-tab-container");
|
||||||
|
|
||||||
|
const el = $('.chrome-tabs')[0];
|
||||||
|
const chromeTabs = new ChromeTabs();
|
||||||
|
chromeTabs.init(el);
|
||||||
|
|
||||||
|
el.addEventListener('activeTabChange', ({detail}) => console.log('Active tab changed', detail.tabEl));
|
||||||
|
el.addEventListener('tabAdd', ({detail}) => console.log('Tab added', detail.tabEl));
|
||||||
|
el.addEventListener('tabRemove', ({detail}) => console.log('Tab removed', detail.tabEl));
|
||||||
|
|
||||||
const componentClasses = {
|
const componentClasses = {
|
||||||
'code': noteDetailCode,
|
'code': noteDetailCode,
|
||||||
@ -26,17 +34,17 @@ const componentClasses = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class NoteContext {
|
class NoteContext {
|
||||||
constructor(noteId) {
|
constructor(note) {
|
||||||
/** @type {NoteFull} */
|
/** @type {NoteFull} */
|
||||||
this.note = null;
|
this.note = note;
|
||||||
this.noteId = noteId;
|
this.noteId = note.noteId;
|
||||||
this.$noteTab = $noteTabsContainer.find(`[data-note-id="${noteId}"]`);
|
this.$noteTabContent = $noteTabContentsContainer.find(`[data-note-id="${this.noteId}"]`);
|
||||||
this.$noteTitle = this.$noteTab.find(".note-title");
|
this.$noteTitle = this.$noteTabContent.find(".note-title");
|
||||||
this.$noteDetailComponents = this.$noteTab.find(".note-detail-component");
|
this.$noteDetailComponents = this.$noteTabContent.find(".note-detail-component");
|
||||||
this.$protectButton = this.$noteTab.find(".protect-button");
|
this.$protectButton = this.$noteTabContent.find(".protect-button");
|
||||||
this.$unprotectButton = this.$noteTab.find(".unprotect-button");
|
this.$unprotectButton = this.$noteTabContent.find(".unprotect-button");
|
||||||
this.$childrenOverview = this.$noteTab.find(".children-overview");
|
this.$childrenOverview = this.$noteTabContent.find(".children-overview");
|
||||||
this.$scriptArea = this.$noteTab.find(".note-detail-script-area");
|
this.$scriptArea = this.$noteTabContent.find(".note-detail-script-area");
|
||||||
this.isNoteChanged = false;
|
this.isNoteChanged = false;
|
||||||
this.components = {};
|
this.components = {};
|
||||||
|
|
||||||
@ -47,6 +55,19 @@ class NoteContext {
|
|||||||
|
|
||||||
treeService.setNoteTitle(this.noteId, title);
|
treeService.setNoteTitle(this.noteId, title);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.tab = chromeTabs.addTab({
|
||||||
|
title: note.title,
|
||||||
|
favicon: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setNote(note) {
|
||||||
|
this.noteId = note.noteId;
|
||||||
|
this.note = note;
|
||||||
|
this.$noteTabContent.attr('data-note-id', note.noteId);
|
||||||
|
|
||||||
|
chromeTabs.updateTab(this.tab, {title: note.title});
|
||||||
}
|
}
|
||||||
|
|
||||||
getComponent(type) {
|
getComponent(type) {
|
||||||
@ -135,20 +156,20 @@ class NoteContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateNoteView() {
|
updateNoteView() {
|
||||||
this.$noteTab.toggleClass("protected", this.note.isProtected);
|
this.$noteTabContent.toggleClass("protected", this.note.isProtected);
|
||||||
this.$protectButton.toggleClass("active", this.note.isProtected);
|
this.$protectButton.toggleClass("active", this.note.isProtected);
|
||||||
this.$protectButton.prop("disabled", this.note.isProtected);
|
this.$protectButton.prop("disabled", this.note.isProtected);
|
||||||
this.$unprotectButton.toggleClass("active", !this.note.isProtected);
|
this.$unprotectButton.toggleClass("active", !this.note.isProtected);
|
||||||
this.$unprotectButton.prop("disabled", !this.note.isProtected || !protectedSessionHolder.isProtectedSessionAvailable());
|
this.$unprotectButton.prop("disabled", !this.note.isProtected || !protectedSessionHolder.isProtectedSessionAvailable());
|
||||||
|
|
||||||
for (const clazz of Array.from(this.$noteTab[0].classList)) { // create copy to safely iterate over while removing classes
|
for (const clazz of Array.from(this.$noteTabContent[0].classList)) { // create copy to safely iterate over while removing classes
|
||||||
if (clazz.startsWith("type-") || clazz.startsWith("mime-")) {
|
if (clazz.startsWith("type-") || clazz.startsWith("mime-")) {
|
||||||
this.$noteTab.removeClass(clazz);
|
this.$noteTabContent.removeClass(clazz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$noteTab.addClass(utils.getNoteTypeClass(this.note.type));
|
this.$noteTabContent.addClass(utils.getNoteTypeClass(this.note.type));
|
||||||
this.$noteTab.addClass(utils.getMimeTypeClass(this.note.mime));
|
this.$noteTabContent.addClass(utils.getMimeTypeClass(this.note.mime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import attributeService from "./attributes.js";
|
|||||||
import utils from "./utils.js";
|
import utils from "./utils.js";
|
||||||
import importDialog from "../dialogs/import.js";
|
import importDialog from "../dialogs/import.js";
|
||||||
|
|
||||||
const $noteTabsContainer = $("#note-tab-container");
|
const $noteTabContentsContainer = $("#note-tab-container");
|
||||||
const $savedIndicator = $("#saved-indicator");
|
const $savedIndicator = $("#saved-indicator");
|
||||||
|
|
||||||
let noteChangeDisabled = false;
|
let noteChangeDisabled = false;
|
||||||
@ -43,18 +43,11 @@ async function reload() {
|
|||||||
await loadNoteDetail(getActiveNoteId());
|
await loadNoteDetail(getActiveNoteId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function openInTab(noteId) {
|
||||||
|
await loadNoteDetail(noteId, true);
|
||||||
|
}
|
||||||
|
|
||||||
async function switchToNote(noteId) {
|
async function switchToNote(noteId) {
|
||||||
if (Object.keys(noteContexts).length === 0) {
|
|
||||||
const tabContent = $("#note-tab-content-template").clone();
|
|
||||||
|
|
||||||
tabContent.removeAttr('id');
|
|
||||||
tabContent.attr('data-note-id', noteId);
|
|
||||||
|
|
||||||
$noteTabsContainer.append(tabContent);
|
|
||||||
|
|
||||||
noteContexts[noteId] = new NoteContext(noteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
//if (getActiveNoteId() !== noteId) {
|
//if (getActiveNoteId() !== noteId) {
|
||||||
await saveNotesIfChanged();
|
await saveNotesIfChanged();
|
||||||
|
|
||||||
@ -71,7 +64,7 @@ function onNoteChange(func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function saveNotesIfChanged() {
|
async function saveNotesIfChanged() {
|
||||||
for (const ctx of Object.values(noteContexts)) {
|
for (const ctx of noteContexts) {
|
||||||
await ctx.saveNoteIfChanged();
|
await ctx.saveNoteIfChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,13 +86,15 @@ async function handleProtectedSession() {
|
|||||||
return newSessionCreated;
|
return newSessionCreated;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {Object.<string, NoteContext>} */
|
/** @type {NoteContext[]} */
|
||||||
const noteContexts = {};
|
const noteContexts = [];
|
||||||
|
|
||||||
/** @returns {NoteContext} */
|
/** @returns {NoteContext} */
|
||||||
function getContext(noteId) {
|
function getContext(noteId) {
|
||||||
if (noteId in noteContexts) {
|
const noteContext = noteContexts.find(nc => nc.noteId === noteId);
|
||||||
return noteContexts[noteId];
|
|
||||||
|
if (noteContext) {
|
||||||
|
return noteContext;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new Error(`Can't find note context for ${noteId}`);
|
throw new Error(`Can't find note context for ${noteId}`);
|
||||||
@ -108,21 +103,36 @@ function getContext(noteId) {
|
|||||||
|
|
||||||
/** @returns {NoteContext} */
|
/** @returns {NoteContext} */
|
||||||
function getActiveContext() {
|
function getActiveContext() {
|
||||||
const currentTreeNode = treeService.getActiveNode();
|
for (const ctx of noteContexts) {
|
||||||
|
if (ctx.$noteTabContent.is(":visible")) {
|
||||||
return getContext(currentTreeNode.data.noteId);
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showTab(noteId) {
|
|
||||||
for (const ctx of Object.values(noteContexts)) {
|
|
||||||
ctx.$noteTab.toggle(ctx.noteId === noteId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadNoteDetail(noteId) {
|
function showTab(noteId) {
|
||||||
const ctx = getContext(noteId);
|
for (const ctx of noteContexts) {
|
||||||
|
ctx.$noteTabContent.toggle(ctx.noteId === noteId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadNoteDetail(noteId, newTab = false) {
|
||||||
const loadedNote = await loadNote(noteId);
|
const loadedNote = await loadNote(noteId);
|
||||||
|
|
||||||
|
if (noteContexts.length === 0 || newTab) {
|
||||||
|
const tabContent = $("#note-tab-content-template").clone();
|
||||||
|
|
||||||
|
tabContent.removeAttr('id');
|
||||||
|
tabContent.attr('data-note-id', noteId);
|
||||||
|
|
||||||
|
$noteTabContentsContainer.append(tabContent);
|
||||||
|
|
||||||
|
noteContexts.push(new NoteContext(loadedNote));
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = getActiveContext();
|
||||||
|
ctx.setNote(loadedNote);
|
||||||
|
|
||||||
// we will try to render the new note only if it's still the active one in the tree
|
// we will try to render the new note only if it's still the active one in the tree
|
||||||
// this is useful when user quickly switches notes (by e.g. holding down arrow) so that we don't
|
// this is useful when user quickly switches notes (by e.g. holding down arrow) so that we don't
|
||||||
// try to render all those loaded notes one after each other. This only guarantees that correct note
|
// try to render all those loaded notes one after each other. This only guarantees that correct note
|
||||||
@ -247,11 +257,11 @@ messagingService.subscribeToSyncMessages(syncData => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$noteTabsContainer.on("dragover", e => e.preventDefault());
|
$noteTabContentsContainer.on("dragover", e => e.preventDefault());
|
||||||
|
|
||||||
$noteTabsContainer.on("dragleave", e => e.preventDefault());
|
$noteTabContentsContainer.on("dragleave", e => e.preventDefault());
|
||||||
|
|
||||||
$noteTabsContainer.on("drop", e => {
|
$noteTabContentsContainer.on("drop", e => {
|
||||||
importDialog.uploadFiles(getActiveNoteId(), e.originalEvent.dataTransfer.files, {
|
importDialog.uploadFiles(getActiveNoteId(), e.originalEvent.dataTransfer.files, {
|
||||||
safeImport: true,
|
safeImport: true,
|
||||||
shrinkImages: true,
|
shrinkImages: true,
|
||||||
@ -269,6 +279,7 @@ setInterval(saveNotesIfChanged, 3000);
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
reload,
|
reload,
|
||||||
|
openInTab,
|
||||||
switchToNote,
|
switchToNote,
|
||||||
loadNote,
|
loadNote,
|
||||||
getActiveNote,
|
getActiveNote,
|
||||||
|
@ -3,65 +3,74 @@ import server from "./server.js";
|
|||||||
import protectedSessionHolder from "./protected_session_holder.js";
|
import protectedSessionHolder from "./protected_session_holder.js";
|
||||||
import noteDetailService from "./note_detail.js";
|
import noteDetailService from "./note_detail.js";
|
||||||
|
|
||||||
const $component = $('#note-detail-file');
|
class NoteDetailFile {
|
||||||
|
/**
|
||||||
|
* @param {NoteContext} ctx
|
||||||
|
*/
|
||||||
|
constructor(ctx) {
|
||||||
|
this.$component = ctx.$noteTabContent.find('.note-detail-file');
|
||||||
|
this.$fileNoteId = ctx.$noteTabContent.find(".file-note-id");
|
||||||
|
this.$fileName = ctx.$noteTabContent.find(".file-filename");
|
||||||
|
this.$fileType = ctx.$noteTabContent.find(".file-filetype");
|
||||||
|
this.$fileSize = ctx.$noteTabContent.find(".file-filesize");
|
||||||
|
this.$previewRow = ctx.$noteTabContent.find(".file-preview-row");
|
||||||
|
this.$previewContent = ctx.$noteTabContent.find(".file-preview-content");
|
||||||
|
this.$downloadButton = ctx.$noteTabContent.find(".file-download");
|
||||||
|
this.$openButton = ctx.$noteTabContent.find(".file-open");
|
||||||
|
|
||||||
const $fileNoteId = $("#file-note-id");
|
this.$downloadButton.click(() => utils.download(this.getFileUrl()));
|
||||||
const $fileName = $("#file-filename");
|
|
||||||
const $fileType = $("#file-filetype");
|
|
||||||
const $fileSize = $("#file-filesize");
|
|
||||||
const $previewRow = $("#file-preview-row");
|
|
||||||
const $previewContent = $("#file-preview-content");
|
|
||||||
const $downloadButton = $("#file-download");
|
|
||||||
const $openButton = $("#file-open");
|
|
||||||
|
|
||||||
async function show() {
|
this.$openButton.click(() => {
|
||||||
const activeNote = noteDetailService.getActiveNote();
|
if (utils.isElectron()) {
|
||||||
|
const open = require("open");
|
||||||
|
|
||||||
const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
|
open(this.getFileUrl());
|
||||||
const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
|
}
|
||||||
|
else {
|
||||||
$component.show();
|
window.location.href = this.getFileUrl();
|
||||||
|
}
|
||||||
$fileNoteId.text(activeNote.noteId);
|
});
|
||||||
$fileName.text(attributeMap.originalFileName || "?");
|
|
||||||
$fileSize.text((attributeMap.fileSize || "?") + " bytes");
|
|
||||||
$fileType.text(activeNote.mime);
|
|
||||||
|
|
||||||
if (activeNote.content) {
|
|
||||||
$previewRow.show();
|
|
||||||
$previewContent.text(activeNote.content);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$previewRow.hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// open doesn't work for protected notes since it works through browser which isn't in protected session
|
async show() {
|
||||||
$openButton.toggle(!activeNote.isProtected);
|
const activeNote = noteDetailService.getActiveNote();
|
||||||
|
|
||||||
|
const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
|
||||||
|
const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
|
||||||
|
|
||||||
|
this.$component.show();
|
||||||
|
|
||||||
|
this.$fileNoteId.text(activeNote.noteId);
|
||||||
|
this.$fileName.text(attributeMap.originalFileName || "?");
|
||||||
|
this.$fileSize.text((attributeMap.fileSize || "?") + " bytes");
|
||||||
|
this.$fileType.text(activeNote.mime);
|
||||||
|
|
||||||
|
if (activeNote.content) {
|
||||||
|
this.$previewRow.show();
|
||||||
|
this.$previewContent.text(activeNote.content);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.$previewRow.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
// open doesn't work for protected notes since it works through browser which isn't in protected session
|
||||||
|
this.$openButton.toggle(!activeNote.isProtected);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFileUrl() {
|
||||||
|
// electron needs absolute URL so we extract current host, port, protocol
|
||||||
|
return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
|
||||||
|
}
|
||||||
|
|
||||||
|
getContent() {}
|
||||||
|
|
||||||
|
focus() {}
|
||||||
|
|
||||||
|
onNoteChange() {}
|
||||||
|
|
||||||
|
cleanup() {}
|
||||||
|
|
||||||
|
scrollToTop() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
$downloadButton.click(() => utils.download(getFileUrl()));
|
export default NoteDetailFile;
|
||||||
|
|
||||||
$openButton.click(() => {
|
|
||||||
if (utils.isElectron()) {
|
|
||||||
const open = require("open");
|
|
||||||
|
|
||||||
open(getFileUrl());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
window.location.href = getFileUrl();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function getFileUrl() {
|
|
||||||
// electron needs absolute URL so we extract current host, port, protocol
|
|
||||||
return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
show,
|
|
||||||
getContent: () => null,
|
|
||||||
focus: () => null,
|
|
||||||
onNoteChange: () => null,
|
|
||||||
cleanup: () => null,
|
|
||||||
scrollToTop: () => null
|
|
||||||
}
|
|
@ -1,75 +1,85 @@
|
|||||||
import utils from "./utils.js";
|
import utils from "./utils.js";
|
||||||
import protectedSessionHolder from "./protected_session_holder.js";
|
|
||||||
import noteDetailService from "./note_detail.js";
|
import noteDetailService from "./note_detail.js";
|
||||||
import infoService from "./info.js";
|
import infoService from "./info.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
|
|
||||||
const $component = $('#note-detail-image');
|
class NoteDetailImage {
|
||||||
const $imageWrapper = $('#note-detail-image-wrapper');
|
/**
|
||||||
const $imageView = $('#note-detail-image-view');
|
* @param {NoteContext} ctx
|
||||||
|
*/
|
||||||
|
constructor(ctx) {
|
||||||
|
this.$component = ctx.$noteTabContent.find('.note-detail-image');
|
||||||
|
this.$imageWrapper = ctx.$noteTabContent.find('.note-detail-image-wrapper');
|
||||||
|
this.$imageView = ctx.$noteTabContent.find('.note-detail-image-view');
|
||||||
|
this.$copyToClipboardButton = ctx.$noteTabContent.find(".image-copy-to-clipboard");
|
||||||
|
this.$fileName = ctx.$noteTabContent.find(".image-filename");
|
||||||
|
this.$fileType = ctx.$noteTabContent.find(".image-filetype");
|
||||||
|
this.$fileSize = ctx.$noteTabContent.find(".image-filesize");
|
||||||
|
|
||||||
const $imageDownloadButton = $("#image-download");
|
this.$imageDownloadButton = ctx.$noteTabContent.find(".image-download");
|
||||||
const $copyToClipboardButton = $("#image-copy-to-clipboard");
|
this.$imageDownloadButton.click(() => utils.download(this.getFileUrl()));
|
||||||
const $fileName = $("#image-filename");
|
|
||||||
const $fileType = $("#image-filetype");
|
|
||||||
const $fileSize = $("#image-filesize");
|
|
||||||
|
|
||||||
async function show() {
|
this.$copyToClipboardButton.click(() => {
|
||||||
const activeNote = noteDetailService.getActiveNote();
|
this.$imageWrapper.attr('contenteditable','true');
|
||||||
|
|
||||||
const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
|
try {
|
||||||
const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
|
this.selectImage(this.$imageWrapper.get(0));
|
||||||
|
|
||||||
$component.show();
|
const success = document.execCommand('copy');
|
||||||
|
|
||||||
$fileName.text(attributeMap.originalFileName || "?");
|
if (success) {
|
||||||
$fileSize.text((attributeMap.fileSize || "?") + " bytes");
|
infoService.showMessage("Image copied to the clipboard");
|
||||||
$fileType.text(activeNote.mime);
|
}
|
||||||
|
else {
|
||||||
$imageView.prop("src", `api/images/${activeNote.noteId}/${activeNote.title}`);
|
infoService.showAndLogError("Could not copy the image to clipboard.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$imageDownloadButton.click(() => utils.download(getFileUrl()));
|
finally {
|
||||||
|
window.getSelection().removeAllRanges();
|
||||||
function selectImage(element) {
|
this.$imageWrapper.removeAttr('contenteditable');
|
||||||
const selection = window.getSelection();
|
}
|
||||||
const range = document.createRange();
|
});
|
||||||
range.selectNodeContents(element);
|
|
||||||
selection.removeAllRanges();
|
|
||||||
selection.addRange(range);
|
|
||||||
}
|
|
||||||
|
|
||||||
$copyToClipboardButton.click(() => {
|
|
||||||
$imageWrapper.attr('contenteditable','true');
|
|
||||||
|
|
||||||
try {
|
|
||||||
selectImage($imageWrapper.get(0));
|
|
||||||
|
|
||||||
const success = document.execCommand('copy');
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
infoService.showMessage("Image copied to the clipboard");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
infoService.showAndLogError("Could not copy the image to clipboard.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
window.getSelection().removeAllRanges();
|
|
||||||
$imageWrapper.removeAttr('contenteditable');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function getFileUrl() {
|
async show() {
|
||||||
// electron needs absolute URL so we extract current host, port, protocol
|
const activeNote = noteDetailService.getActiveNote();
|
||||||
return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
|
|
||||||
|
const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
|
||||||
|
const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
|
||||||
|
|
||||||
|
this.$component.show();
|
||||||
|
|
||||||
|
this.$fileName.text(attributeMap.originalFileName || "?");
|
||||||
|
this.$fileSize.text((attributeMap.fileSize || "?") + " bytes");
|
||||||
|
this.$fileType.text(activeNote.mime);
|
||||||
|
|
||||||
|
this.$imageView.prop("src", `api/images/${activeNote.noteId}/${activeNote.title}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectImage(element) {
|
||||||
|
const selection = window.getSelection();
|
||||||
|
const range = document.createRange();
|
||||||
|
range.selectNodeContents(element);
|
||||||
|
selection.removeAllRanges();
|
||||||
|
selection.addRange(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFileUrl() {
|
||||||
|
// electron needs absolute URL so we extract current host, port, protocol
|
||||||
|
return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
|
||||||
|
}
|
||||||
|
|
||||||
|
getContent() {}
|
||||||
|
|
||||||
|
focus() {}
|
||||||
|
|
||||||
|
onNoteChange() {}
|
||||||
|
|
||||||
|
cleanup() {}
|
||||||
|
|
||||||
|
scrollToTop() {
|
||||||
|
this.$component.scrollTop(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default NoteDetailImage
|
||||||
show,
|
|
||||||
getContent: () => null,
|
|
||||||
focus: () => null,
|
|
||||||
onNoteChange: () => null,
|
|
||||||
cleanup: () => null,
|
|
||||||
scrollToTop: () => $component.scrollTop(0)
|
|
||||||
}
|
|
@ -9,7 +9,7 @@ class NoteDetailText {
|
|||||||
*/
|
*/
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.$component = ctx.$noteTab.find('.note-detail-text');
|
this.$component = ctx.$noteTabContent.find('.note-detail-text');
|
||||||
this.textEditor = null;
|
this.textEditor = null;
|
||||||
|
|
||||||
this.$component.on("dblclick", "img", e => {
|
this.$component.on("dblclick", "img", e => {
|
||||||
@ -53,7 +53,7 @@ class NoteDetailText {
|
|||||||
|
|
||||||
this.$component.show();
|
this.$component.show();
|
||||||
|
|
||||||
this.textEditor.setData(this.ctx.note.content);
|
// this.textEditor.setData(this.ctx.note.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
getContent() {
|
getContent() {
|
||||||
|
@ -485,7 +485,7 @@ function initFancyTree(tree) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$tree.on('contextmenu', '.fancytree-node', function(e) {
|
$tree.on('contextmenu', '.fancytree-node', function(e) {
|
||||||
treeContextMenuService.getContextMenuItems(e).then(contextMenuItems => {
|
treeContextMenuService.getContextMenuItems(e).then(([node, contextMenuItems]) => {
|
||||||
contextMenuWidget.initContextMenu(e, contextMenuItems, treeContextMenuService.selectContextMenuItem);
|
contextMenuWidget.initContextMenu(e, contextMenuItems, treeContextMenuService.selectContextMenuItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import infoService from "./info.js";
|
|||||||
import treeCache from "./tree_cache.js";
|
import treeCache from "./tree_cache.js";
|
||||||
import syncService from "./sync.js";
|
import syncService from "./sync.js";
|
||||||
import hoistedNoteService from './hoisted_note.js';
|
import hoistedNoteService from './hoisted_note.js';
|
||||||
|
import noteDetailService from './note_detail.js';
|
||||||
|
|
||||||
let clipboardIds = [];
|
let clipboardIds = [];
|
||||||
let clipboardMode = null;
|
let clipboardMode = null;
|
||||||
@ -103,6 +104,7 @@ async function getTopLevelItems(event) {
|
|||||||
const insertChildNoteEnabled = note.type !== 'search';
|
const insertChildNoteEnabled = note.type !== 'search';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
{ title: "Open in new tab", cmd: "openInTab", uiIcon: "empty" },
|
||||||
{ title: "Insert note after <kbd>Ctrl+O</kbd>", cmd: "insertNoteAfter", uiIcon: "plus",
|
{ title: "Insert note after <kbd>Ctrl+O</kbd>", cmd: "insertNoteAfter", uiIcon: "plus",
|
||||||
items: insertNoteAfterEnabled ? getNoteTypeItems("insertNoteAfter") : null,
|
items: insertNoteAfterEnabled ? getNoteTypeItems("insertNoteAfter") : null,
|
||||||
enabled: insertNoteAfterEnabled },
|
enabled: insertNoteAfterEnabled },
|
||||||
@ -143,9 +145,7 @@ async function getTopLevelItems(event) {
|
|||||||
async function getContextMenuItems(event) {
|
async function getContextMenuItems(event) {
|
||||||
const items = await getTopLevelItems(event);
|
const items = await getTopLevelItems(event);
|
||||||
|
|
||||||
// Activate node on right-click
|
|
||||||
const node = $.ui.fancytree.getNode(event);
|
const node = $.ui.fancytree.getNode(event);
|
||||||
node.setActive();
|
|
||||||
|
|
||||||
// right click resets selection to just this node
|
// right click resets selection to just this node
|
||||||
// this is important when e.g. you right click on a note while having different note active
|
// this is important when e.g. you right click on a note while having different note active
|
||||||
@ -153,14 +153,17 @@ async function getContextMenuItems(event) {
|
|||||||
node.setSelected(true);
|
node.setSelected(true);
|
||||||
treeService.clearSelectedNodes();
|
treeService.clearSelectedNodes();
|
||||||
|
|
||||||
return items;
|
return [node, items];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function selectContextMenuItem(event, cmd) {
|
async function selectContextMenuItem(event, cmd) {
|
||||||
// context menu is always triggered on current node
|
// context menu is always triggered on current node
|
||||||
const node = treeService.getActiveNode();
|
const node = treeService.getActiveNode();
|
||||||
|
|
||||||
if (cmd.startsWith("insertNoteAfter")) {
|
if (cmd === 'openInTab') {
|
||||||
|
noteDetailService.openInTab(node.data.noteId);
|
||||||
|
}
|
||||||
|
else if (cmd.startsWith("insertNoteAfter")) {
|
||||||
const parentNoteId = node.data.parentNoteId;
|
const parentNoteId = node.data.parentNoteId;
|
||||||
const isProtected = await treeUtils.getParentProtectedStatus(node);
|
const isProtected = await treeUtils.getParentProtectedStatus(node);
|
||||||
const type = cmd.split("_")[1];
|
const type = cmd.split("_")[1];
|
||||||
|
@ -31,7 +31,6 @@ body {
|
|||||||
#note-tab-container {
|
#note-tab-container {
|
||||||
grid-area: tab-container;
|
grid-area: tab-container;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
min-height: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-box {
|
#search-box {
|
||||||
@ -148,7 +147,7 @@ li.dropdown-submenu:hover > ul.dropdown-menu {
|
|||||||
border: 1px solid var(--main-border-color);
|
border: 1px solid var(--main-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-info-table td, #note-info-table th {
|
.note-info-table td, .note-info-table th {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ html, body {
|
|||||||
padding-left: 35px;
|
padding-left: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-title-row {
|
.note-title-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
@ -48,7 +48,7 @@ button.close {
|
|||||||
color: var(--main-text-color) !important;
|
color: var(--main-text-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-title {
|
.note-title {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
font-size: 150%;
|
font-size: 150%;
|
||||||
@ -95,7 +95,7 @@ ul.fancytree-container {
|
|||||||
content: "\e9ba";
|
content: "\e9ba";
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-title[readonly] {
|
.note-title[readonly] {
|
||||||
background: inherit;
|
background: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,13 +103,17 @@ ul.fancytree-container {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#note-tab-content-template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.note-tab-content {
|
.note-tab-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-detail-component-wrapper {
|
.note-detail-component-wrapper {
|
||||||
flex-grow: 100;
|
flex-grow: 100;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@ -125,14 +129,14 @@ ul.fancytree-container {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-detail-text h1 { font-size: 2.0em; }
|
.note-detail-text h1 { font-size: 2.0em; }
|
||||||
#note-detail-text h2 { font-size: 1.8em; }
|
.note-detail-text h2 { font-size: 1.8em; }
|
||||||
#note-detail-text h3 { font-size: 1.6em; }
|
.note-detail-text h3 { font-size: 1.6em; }
|
||||||
#note-detail-text h4 { font-size: 1.4em; }
|
.note-detail-text h4 { font-size: 1.4em; }
|
||||||
#note-detail-text h5 { font-size: 1.2em; }
|
.note-detail-text h5 { font-size: 1.2em; }
|
||||||
#note-detail-text h6 { font-size: 1.1em; }
|
.note-detail-text h6 { font-size: 1.1em; }
|
||||||
|
|
||||||
#note-detail-text {
|
.note-detail-text {
|
||||||
border: 0 !important;
|
border: 0 !important;
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
/* This is because with empty content height of editor is 0 and it's impossible to click into it */
|
/* This is because with empty content height of editor is 0 and it's impossible to click into it */
|
||||||
@ -142,7 +146,7 @@ ul.fancytree-container {
|
|||||||
font-family: var(--detail-text-font-family);
|
font-family: var(--detail-text-font-family);
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-detail-text p:first-child, #note-detail-text::before {
|
.note-detail-text p:first-child, .note-detail-text::before {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,12 +356,12 @@ div.ui-tooltip {
|
|||||||
color: #aaa !important;
|
color: #aaa !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-detail-code {
|
.note-detail-code {
|
||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-detail-render {
|
.note-detail-render {
|
||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,7 +380,7 @@ div.ui-tooltip {
|
|||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-type-dropdown {
|
.note-type-dropdown {
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
@ -403,7 +407,7 @@ div.ui-tooltip {
|
|||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#file-table th, #file-table td {
|
.file-table th, .file-table td {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-size: larger;
|
font-size: larger;
|
||||||
}
|
}
|
||||||
@ -464,7 +468,7 @@ div.ui-tooltip {
|
|||||||
background-color: var(--button-disabled-background-color) !important;
|
background-color: var(--button-disabled-background-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-path-list a.current {
|
.note-path-list a.current {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,12 +477,12 @@ button.icon-button {
|
|||||||
padding: 2px;
|
padding: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-actions {
|
.note-actions {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-actions .dropdown-menu {
|
.note-actions .dropdown-menu {
|
||||||
width: 15em;
|
width: 15em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,7 +499,7 @@ button.icon-button {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-detail-promoted-attributes {
|
.note-detail-promoted-attributes {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
/* setting the display to block since "table" doesn't support scrolling */
|
/* setting the display to block since "table" doesn't support scrolling */
|
||||||
display: block;
|
display: block;
|
||||||
@ -505,15 +509,15 @@ button.icon-button {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-detail-promoted-attributes td, #note-detail-promoted-attributes th {
|
.note-detail-promoted-attributes td, .note-detail-promoted-attributes th {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-detail-image {
|
.note-detail-image {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-detail-image-view {
|
.note-detail-image-view {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,7 +525,7 @@ pre:not(.CodeMirror-line) {
|
|||||||
color: var(--main-text-color) !important;
|
color: var(--main-text-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#file-preview-content {
|
.file-preview-content {
|
||||||
background-color: var(--accented-background-color);
|
background-color: var(--accented-background-color);
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
@ -580,7 +584,7 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#note-detail-render-help {
|
.note-detail-render-help {
|
||||||
margin: 50px;
|
margin: 50px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<th>File size:</th>
|
<th>File size:</th>
|
||||||
<td class="file-filesize"></td>
|
<td class="file-filesize"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="file-preview-row">
|
<tr class="file-preview-row">
|
||||||
<th>Preview:</th>
|
<th>Preview:</th>
|
||||||
<td>
|
<td>
|
||||||
<pre class="file-preview-content"></pre>
|
<pre class="file-preview-content"></pre>
|
||||||
|
@ -1,20 +1,5 @@
|
|||||||
<div class="chrome-tabs">
|
<div class="chrome-tabs">
|
||||||
<div class="chrome-tabs-content">
|
<div class="chrome-tabs-content"></div>
|
||||||
<div class="chrome-tab">
|
|
||||||
<div class="chrome-tab-content">
|
|
||||||
<div class="chrome-tab-title">Google</div>
|
|
||||||
<div class="chrome-tab-drag-handle"></div>
|
|
||||||
<div class="chrome-tab-close"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="chrome-tab" active>
|
|
||||||
<div class="chrome-tab-content">
|
|
||||||
<div class="chrome-tab-title">Facebook</div>
|
|
||||||
<div class="chrome-tab-drag-handle"></div>
|
|
||||||
<div class="chrome-tab-close"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="note-tab-container">
|
<div id="note-tab-container">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user