1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-25 08:09:43 +02:00

Merge pull request #83 from documize/metreon

Problem: document UX is not that intuitive and impactful
This commit is contained in:
Harvey Kandola 2017-03-12 15:23:19 +00:00 committed by GitHub
commit b394d926fc
278 changed files with 24758 additions and 23376 deletions

View file

@ -6,6 +6,7 @@
"-Promise",
"moment",
"$",
"jQuery",
"_",
"is",
"Mousetrap",
@ -19,7 +20,8 @@
"Dropzone",
"Sortable",
"datetimepicker",
"Waypoint"
"Waypoint",
"velocity"
],
"browser": true,
"boss": true,

View file

@ -31,6 +31,10 @@ export default Ember.Component.extend(TooltipMixin, {
{ label: 'Attachment', selected: false },
{ label: 'Search', selected: false }
],
contentLinkerButtonId: Ember.computed('page', function () {
let page = this.get('page');
return `content-linker-button-${page.id}`;
}),
showSections: Ember.computed('tabs.@each.selected', function () {
return this.get('tabs').findBy('label', 'Section').selected;

View file

@ -1,68 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
export default Ember.Component.extend({
sortedItems: [],
didReceiveAttrs() {
let editors = this.get('activity.editors');
let viewers = this.get('activity.viewers');
let pages = this.get('pages');
let sorted = [];
if (is.null(editors)) {
editors = [];
}
if (is.null(viewers)) {
viewers = [];
}
viewers.forEach((item) => {
Ember.set(item, 'changeLabel', "viewed");
Ember.set(item, "viewed", true);
sorted.pushObject({ date: item.created, item: item });
});
editors.forEach(function (item) {
Ember.set(item, "added", item.action === "add-page");
Ember.set(item, "changed", item.action === "update-page");
Ember.set(item, "deleted", item.action === "remove-page");
let page = pages.findBy('id', item.pageId);
let title = "";
if (item.deleted || is.undefined(page)) {
title = "removed section";
} else {
if (item.added) {
title = "added " + page.get('title');
}
if (item.changed) {
title = "changed " + page.get('title');
}
}
Ember.set(item, 'changeLabel', title);
let exists = sorted.findBy('item.pageId', item.pageId);
if (is.undefined(exists)) {
sorted.pushObject({ date: item.created, item: item });
}
});
this.set('sortedItems', _.sortBy(sorted, 'date').reverse());
}
});

View file

@ -0,0 +1,53 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import NotifierMixin from '../../mixins/notifier';
import TooltipMixin from '../../mixins/tooltip';
const {
computed,
} = Ember;
export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
documentService: Ember.inject.service('document'),
editMode: false,
docName: '',
docExcerpt: '',
hasNameError: computed.empty('docName'),
hasExcerptError: computed.empty('docExcerpt'),
actions: {
toggleEdit() {
this.set('docName', this.get('document.name'));
this.set('docExcerpt', this.get('document.excerpt'));
this.set('editMode', true);
},
onSaveDocument() {
if (this.get('hasNameError') || this.get('hasExcerptError')) {
return;
}
this.set('document.name', this.get('docName'));
this.set('document.excerpt', this.get('docExcerpt'));
this.showNotification('Saved');
this.get('documentService').save(this.get('document'));
this.set('editMode', false);
},
cancel() {
this.set('editMode', false);
}
}
});

View file

@ -12,7 +12,7 @@
import Ember from 'ember';
export default Ember.Component.extend({
revision: {},
revision: null,
hasDiff: Ember.computed('diff', function () {
return this.get('diff').length > 0;
}),
@ -20,38 +20,28 @@ export default Ember.Component.extend({
didReceiveAttrs() {
let revisions = this.get('revisions');
revisions.forEach((revision) => {
Ember.set(revision, 'deleted', revision.revisions === 0);
revisions.forEach((r) => {
Ember.set(r, 'deleted', r.revisions === 0);
Ember.set(r, 'label', `${r.created} - ${r.firstname} ${r.lastname} - ${r.title}`);
});
if (revisions.length > 0 && is.null(this.get('revision'))) {
this.send('onSelectRevision', revisions[0]);
}
this.set('revisions', revisions);
},
didInsertElement() {
this._super(...arguments);
this.eventBus.subscribe('resized', this, 'sizeSidebar');
this.sizeSidebar();
},
willDestroyElement() {
this.eventBus.unsubscribe('resized');
},
sizeSidebar() {
let size = $(window).height() - 200;
this.$('.document-history > .sidebar').css('height', size + "px");
},
actions: {
getDiff(revision) {
onSelectRevision(revision) {
this.set('revision', revision);
if (!revision.deleted) {
this.attrs.onFetchDiff(revision.pageId, revision.id);
}
},
rollback() {
onRollback() {
let revision = this.get('revision');
this.attrs.onRollback(revision.pageId, revision.id);
}

View file

@ -0,0 +1,84 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import NotifierMixin from '../../mixins/notifier';
import TooltipMixin from '../../mixins/tooltip';
export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
documentService: Ember.inject.service('document'),
sectionService: Ember.inject.service('section'),
editMode: false,
didReceiveAttrs() {
this._super(...arguments);
let page = this.get('page');
this.get('documentService').getPageMeta(page.get('documentId'), page.get('id')).then((meta) => {
this.set('meta', meta);
if (this.get('toEdit') === this.get('page.id') && this.get('isEditor')) {
this.send('onEdit');
}
});
},
actions: {
onSavePage(page, meta) {
this.set('page', page);
this.set('meta', meta);
this.set('editMode', false);
this.get('onSavePage')(page, meta);
},
onSavePageAsBlock(block) {
this.attrs.onSavePageAsBlock(block);
},
onCopyPage(documentId) {
this.attrs.onCopyPage(this.get('page.id'), documentId);
},
onMovePage(documentId) {
this.attrs.onMovePage(this.get('page.id'), documentId);
},
onDeletePage(deleteChildren) {
let page = this.get('page');
if (is.undefined(page)) {
return;
}
let params = {
id: page.get('id'),
title: page.get('title'),
children: deleteChildren
};
this.attrs.onDeletePage(params);
},
onEdit() {
if (this.get('editMode')) {
return;
}
this.get('toEdit', '');
// this.set('pageId', this.get('page.id'));
this.set('editMode', true);
},
onCancelEdit() {
this.set('editMode', false);
}
}
});

View file

@ -1,124 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import TooltipMixin from '../../mixins/tooltip';
import NotifierMixin from '../../mixins/notifier';
export default Ember.Component.extend(TooltipMixin, NotifierMixin, {
documentService: Ember.inject.service('document'),
sectionService: Ember.inject.service('section'),
document: {},
folder: {},
showToc: true,
showSections: false,
showScrollTool: false,
showingSections: false,
init() {
this._super(...arguments);
this.get('sectionService').getSpaceBlocks(this.get('folder.id')).then((b) => {
this.set('blocks', b);
});
},
didRender() {
if (this.session.authenticated) {
this.addTooltip(document.getElementById("section-tool"));
}
},
didInsertElement() {
this.eventBus.subscribe('resized', this, 'positionTool');
this.eventBus.subscribe('scrolled', this, 'positionTool');
},
willDestroyElement() {
this.eventBus.unsubscribe('resized');
this.eventBus.unsubscribe('scrolled');
this.destroyTooltips();
},
positionTool() {
if (this.get('isDestroyed') || this.get('isDestroying')) {
return;
}
let s = $(".scroll-tool");
let windowpos = $(window).scrollTop();
if (windowpos >= 300) {
this.set('showScrollTool', true);
s.addClass("stuck-tool");
s.css('left', parseInt($(".zone-navigation").css('width')) + parseInt($(".zone-sidebar").css('width')) - 16 + 'px');
} else {
this.set('showScrollTool', false);
s.removeClass("stuck-tool");
}
},
actions: {
// Page up - above pages shunt down.
onPageSequenceChange(pendingChanges) {
this.attrs.changePageSequence(pendingChanges);
},
// Move down - pages below shift up.
onPageLevelChange(pendingChanges) {
this.attrs.changePageLevel(pendingChanges);
},
gotoPage(id) {
return this.attrs.gotoPage(id);
},
showToc() {
this.set('showToc', true);
this.set('showSections', false);
this.set('showingSections', false);
},
showSections() {
this.set('showToc', false);
this.set('showSections', true);
this.set('showingSections', true);
},
onCancel() {
this.send('showToc');
this.set('showingSections', false);
},
onAddSection(section) {
this.send('showToc');
this.attrs.onAddSection(section);
},
onInsertBlock(block) {
this.send('showToc');
this.attrs.onInsertBlock(block);
},
onDeleteBlock(id) {
this.set('blocks', this.get('blocks').filter((item) => item.get('id') !== id));
this.attrs.onDeleteBlock(id);
},
scrollTop() {
this.set('showScrollTool', false);
$("html,body").animate({
scrollTop: 0
}, 500, "linear");
}
}
});

View file

@ -19,52 +19,63 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
editMode: false,
didReceiveAttrs(){
if (this.get('mode') === 'edit') {
this.send('onEdit');
}
this.audit.record("viewed-document-section-" + this.get('model.page.contentType'));
},
didInsertElement() {
let self = this;
this.get('sectionService').refresh(this.get('model.document.id')).then(function (changes) {
changes.forEach(function (newPage) {
let oldPage = self.get('model.page');
if (!_.isUndefined(oldPage) && oldPage.get('id') === newPage.get('id')) {
this.get('sectionService').refresh(this.get('document.id')).then((changes) => {
if (this.get('isDestroyed') || this.get('isDestroying')) {
return;
}
let oldPage = this.get('page');
if (is.undefined(changes) || is.undefined(oldPage)) {
return;
}
changes.forEach((newPage) => {
if (oldPage.get('id') === newPage.get('id')) {
oldPage.set('body', newPage.get('body'));
oldPage.set('revised', newPage.get('revised'));
self.showNotification(`Refreshed ${oldPage.get('title')}`);
this.showNotification(`Refreshed ${oldPage.get('title')}`);
}
});
});
},
actions: {
onEdit() {
this.set('viewMode', false);
this.set('editMode', true);
this.set('mode', 'edit');
onExpand() {
this.set('pageId', this.get('page.id'));
this.set('expanded', !this.get('expanded'));
},
onView() {
this.set('viewMode', true);
this.set('editMode', false);
this.set('mode', 'view');
onSavePageAsBlock(block) {
this.attrs.onSavePageAsBlock(block);
},
onCancel() {
this.send('onView');
onCopyPage(documentId) {
this.attrs.onCopyPage(this.get('page.id'), documentId);
},
onAction(page, meta) {
this.get('onAction')(page, meta);
this.send('onView');
onMovePage(documentId) {
this.attrs.onMovePage(this.get('page.id'), documentId);
},
onDeletePage(deleteChildren) {
let page = this.get('page');
onDelete() {
this.get('onDelete')(this.get('model.document'), this.get('model.page'));
return true;
if (is.undefined(page)) {
return;
}
let params = {
id: page.get('id'),
title: page.get('title'),
children: deleteChildren
};
this.attrs.onDeletePage(params);
}
}
});

View file

@ -13,25 +13,61 @@ import Ember from 'ember';
import NotifierMixin from '../../mixins/notifier';
import TooltipMixin from '../../mixins/tooltip';
const {
computed,
} = Ember;
export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
documentService: Ember.inject.service('document'),
sectionService: Ember.inject.service('section'),
appMeta: Ember.inject.service(),
link: Ember.inject.service(),
document: null,
folder: null,
folders: [],
isEditor: false,
hasPages: computed.notEmpty('pages'),
newSectionName: '',
newSectionNameMissing: computed.empty('newSectionName'),
newSectionLocation: '',
beforePage: '',
toEdit: '',
noSections: Ember.computed('pages', function () {
return this.get('pages.length') === 0;
}),
didReceiveAttrs() {
this._super(...arguments);
this.loadBlocks();
Ember.run.schedule('afterRender', () => {
let jumpTo = "#page-" + this.get('pageId');
if (!$(jumpTo).inView()) {
$(jumpTo).velocity("scroll", { duration: 250, offset: -100 });
}
});
},
didRender() {
this._super(...arguments);
this.contentLinkHandler();
},
didInsertElement() {
this._super(...arguments);
$(".start-section:not(.start-section-empty-state)").hoverIntent({interval: 100, over: function() {
// in
$(this).find('.start-button').velocity("transition.slideDownIn", {duration: 300});
}, out: function() {
// out
$(this).find('.start-button').velocity("transition.slideUpOut", {duration: 300});
} });
let self = this;
$(".tooltipped").each(function(i, el) {
self.addTooltip(el);
});
},
willDestroyElement() {
this._super(...arguments);
this.destroyTooltips();
},
@ -45,7 +81,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
// local link? exists?
if ((link.linkType === "section" || link.linkType === "tab") && link.documentId === doc.get('id')) {
let exists = self.get('allPages').findBy('id', link.targetId);
let exists = self.get('pages').findBy('id', link.targetId);
if (_.isUndefined(exists)) {
link.orphan = true;
@ -69,9 +105,58 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
});
},
addSection(model) {
// calculate sequence of page (position in document)
let sequence = 0;
let level = 1;
let beforePage = this.get('beforePage');
if (is.not.null(beforePage)) {
level = beforePage.get('level');
// get any page before the beforePage so we can insert this new section between them
let index = _.findIndex(this.get('pages'), function(p) { return p.get('id') === beforePage.get('id'); });
if (index !== -1) {
let beforeBeforePage = this.get('pages')[index-1];
if (is.not.undefined(beforeBeforePage)) {
sequence = (beforePage.get('sequence') + beforeBeforePage.get('sequence')) / 2;
} else {
sequence = beforePage.get('sequence') / 2;
}
}
}
model.page.sequence = sequence;
model.page.level = level;
this.send('onHideSectionWizard');
return this.get('onInsertSection')(model);
},
loadBlocks() {
this.get('sectionService').getSpaceBlocks(this.get('folder.id')).then((blocks) => {
if (this.get('isDestroyed') || this.get('isDestroying')) {
return;
}
this.set('blocks', blocks);
this.set('hasBlocks', blocks.get('length') > 0);
blocks.forEach((b) => {
b.set('deleteId', `delete-block-button-${b.id}`);
});
});
},
actions: {
onAddBlock(block) {
this.attrs.onAddBlock(block);
onSavePageAsBlock(block) {
const promise = this.attrs.onSavePageAsBlock(block);
promise.then(() => {
this.loadBlocks();
});
},
onCopyPage(pageId, documentId) {
@ -82,26 +167,145 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
this.attrs.onMovePage(pageId, documentId);
},
onDeletePage(id, deleteChildren) {
let page = this.get('pages').findBy("id", id);
if (is.undefined(page)) {
return;
}
let params = {
id: id,
title: page.get('title'),
children: deleteChildren
};
onDeletePage(params) {
this.attrs.onDeletePage(params);
},
onTagChange(tags) {
let doc = this.get('document');
doc.set('tags', tags);
this.get('documentService').save(doc);
}
onSavePage(page, meta) {
this.attrs.onSavePage(page, meta);
},
// Section wizard related
onShowSectionWizard(page) {
if (is.undefined(page)) {
page = { id: '0' };
}
this.set('pageId', '');
let beforePage = this.get('beforePage');
if (is.not.null(beforePage) && $("#new-section-wizard").is(':visible') && beforePage.get('id') === page.id) {
this.send('onHideSectionWizard');
return;
}
this.set('newSectionLocation', page.id);
if (page.id === '0') {
// this handles add section at the end of the document
// because we are not before another page
this.set('beforePage', null);
} else {
this.set('beforePage', page);
}
$("#new-section-wizard").insertAfter(`#add-section-button-${page.id}`);
$("#new-section-wizard").velocity("transition.slideDownIn", {duration: 300, complete:
function() {
$("#new-section-name").focus();
}});
},
onHideSectionWizard() {
this.set('newSectionLocation', '');
this.set('beforePage', null);
$("#new-section-wizard").velocity("transition.slideUpOut", { duration: 300 });
},
onInsertSection(section) {
let sectionName = this.get('newSectionName');
if (is.empty(sectionName)) {
$("#new-section-name").focus();
return;
}
let page = {
documentId: this.get('document.id'),
title: sectionName,
level: 1,
sequence: 0, // calculated elsewhere
body: "",
contentType: section.get('contentType'),
pageType: section.get('pageType')
};
let meta = {
documentId: this.get('document.id'),
rawBody: "",
config: ""
};
let model = {
page: page,
meta: meta
};
this.audit.record("added-section-" + page.contentType);
const promise = this.addSection(model);
promise.then((id) => {
this.set('pageId', id);
if (model.page.pageType === 'section') {
this.set('toEdit', id);
} else {
this.set('toEdit', '');
}
});
},
onInsertBlock(block) {
let sectionName = this.get('newSectionName');
if (is.empty(sectionName)) {
$("#new-section-name").focus();
return;
}
let page = {
documentId: this.get('document.id'),
title: `${block.get('title')}`,
level: 1,
sequence: 0, // calculated elsewhere
body: block.get('body'),
contentType: block.get('contentType'),
pageType: block.get('pageType'),
blockId: block.get('id')
};
let meta = {
documentId: this.get('document.id'),
rawBody: block.get('rawBody'),
config: block.get('config'),
externalSource: block.get('externalSource')
};
let model = {
page: page,
meta: meta
};
this.audit.record("added-content-block-" + block.get('contentType'));
const promise = this.addSection(model);
promise.then((id) => {
this.set('pageId', id);
// if (model.page.pageType === 'section') {
// this.set('toEdit', id);
// } else {
// this.set('toEdit', '');
// }
});
},
onDeleteBlock(id) {
const promise = this.attrs.onDeleteBlock(id);
promise.then(() => {
this.loadBlocks();
});
return true;
}
}
});

View file

@ -1,86 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
export default Ember.Component.extend({
documentService: Ember.inject.service('document'),
revisions: [],
diffReport: "",
busy: false,
currentRevisionId: "",
didReceiveAttrs() {
if (is.undefined(this.get('model'))) {
return;
}
let self = this;
this.get('documentService').getPageRevisions(this.get('model.documentId'), this.get('model.pageId')).then(function(response) {
if (is.array(response)) {
self.set('revisions', response);
if (response.length > 0) {
self.send('produceReport', response[0].id);
}
}
});
},
didRender() {
let self = this;
Ember.run.schedule('afterRender', function() {
Mousetrap.bind('esc', function() {
self.send('cancelAction');
return false;
});
});
},
actions: {
produceReport(revisionId) {
this.set('busy', true);
this.set('diffReport', "");
this.set('currentRevisionId', revisionId);
// visually mark active revision
let revisions = this.get('revisions');
revisions.forEach(function(revision) {
Ember.set(revision, 'selected', false);
});
let revision = _.findWhere(revisions, {
id: revisionId
});
Ember.set(revision, 'selected', true);
let self = this;
this.get('documentService').getPageRevisionDiff(this.get('model.documentId'),
this.get('model.pageId'), revisionId).then(function(response) {
self.set('busy', false);
self.set('diffReport', Ember.String.htmlSafe(response));
});
},
cancelAction() {
this.attrs.editorClose();
},
primaryAction() {
if (this.session.isEditor) {
this.attrs.editorAction(this.get('model.pageId'), this.get('currentRevisionId'));
}
}
}
});

View file

@ -73,21 +73,10 @@ export default Ember.Component.extend(TooltipMixin, {
}),
didRender() {
if (this.get('isEditor')) {
let self = this;
$(".page-action-button").each(function (i, el) {
self.addTooltip(el);
});
}
$("#" + this.get('blockTitleId')).removeClass('error');
$("#" + this.get('blockExcerptId')).removeClass('error');
},
willDestroyElement() {
this.destroyTooltips();
},
actions: {
onMenuOpen() {
if ($('#' + this.get('publishDialogId')).is( ":visible" )) {
@ -103,15 +92,16 @@ export default Ember.Component.extend(TooltipMixin, {
this.set('menuOpen', !this.get('menuOpen'));
},
editPage(id) {
this.attrs.onEditPage(id);
onEdit() {
this.attrs.onEdit();
},
deletePage(id) {
this.attrs.onDeletePage(id, this.get('deleteChildren'));
deletePage() {
this.attrs.onDeletePage(this.get('deleteChildren'));
},
onAddBlock(page) {
onSavePageAsBlock() {
let page = this.get('page');
let titleElem = '#' + this.get('blockTitleId');
let blockTitle = this.get('blockTitle');
if (is.empty(blockTitle)) {
@ -140,7 +130,8 @@ export default Ember.Component.extend(TooltipMixin, {
externalSource: pm.get('externalSource')
};
this.attrs.onAddBlock(block);
this.attrs.onSavePageAsBlock(block);
this.set('menuOpen', false);
this.set('blockTitle', '');
this.set('blockExcerpt', '');
@ -169,7 +160,7 @@ export default Ember.Component.extend(TooltipMixin, {
this.set('selectedDocument', d);
},
onCopyPage(page) {
onCopyPage() {
// can't proceed if no data
if (this.get('documentList.length') === 0) {
return;
@ -180,11 +171,11 @@ export default Ember.Component.extend(TooltipMixin, {
targetDocumentId = this.get('selectedDocument.id');
}
this.attrs.onCopyPage(page.get('id'), targetDocumentId);
this.attrs.onCopyPage(targetDocumentId);
return true;
},
onMovePage(page) {
onMovePage() {
// can't proceed if no data
if (this.get('documentListOthers.length') === 0) {
return;
@ -196,8 +187,8 @@ export default Ember.Component.extend(TooltipMixin, {
let targetDocumentId = this.get('selectedDocument.id');
this.attrs.onMovePage(page.get('id'), targetDocumentId);
this.attrs.onMovePage(targetDocumentId);
return true;
}
}
}
});

View file

@ -1,67 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import NotifierMixin from '../../mixins/notifier';
export default Ember.Component.extend(NotifierMixin, {
display: 'section', // which CSS to use
hasTemplates: false,
hasBlocks: false,
blockMode: false,
didReceiveAttrs() {
let blocks = this.get('blocks');
let blockMode = is.not.undefined(blocks);
this.set('blockMode', blockMode);
if (!blockMode) {
return;
}
this.set('hasBlocks', blocks.get('length') > 0);
blocks.forEach((b) => {
b.set('deleteId', `delete-block-button-${b.id}`);
});
},
didRender() {
let self = this;
Mousetrap.bind('esc', function () {
if (self.get('isDestroyed') || self.get('isDestroying')) {
return;
}
self.send('onCancel');
return false;
});
},
actions: {
onCancel() {
this.attrs.onCancel();
},
addSection(section) {
this.attrs.onAddSection(section);
},
onDeleteBlock(id) {
this.attrs.onDeleteBlock(id);
},
onInsertBlock(block) {
this.attrs.onInsertBlock(block);
}
}
});

View file

@ -0,0 +1,76 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
export default Ember.Component.extend({
documentService: Ember.inject.service('document'),
appMeta: Ember.inject.service(),
sortedItems: [],
didReceiveAttrs() {
this._super(...arguments);
this.get('documentService').getMeta(this.get('document.id')).then((activity) => {
this.set('activity', activity);
let editors = this.get('activity.editors');
let viewers = this.get('activity.viewers');
let pages = this.get('pages');
let sorted = [];
if (is.null(editors)) {
editors = [];
}
if (is.null(viewers)) {
viewers = [];
}
viewers.forEach((item) => {
Ember.set(item, 'changeLabel', "viewed");
Ember.set(item, "viewed", true);
sorted.pushObject({ date: item.created, item: item });
});
editors.forEach(function (item) {
Ember.set(item, "added", item.action === "add-page");
Ember.set(item, "changed", item.action === "update-page");
Ember.set(item, "deleted", item.action === "remove-page");
let page = pages.findBy('id', item.pageId);
let title = "";
if (item.deleted || is.undefined(page)) {
title = "removed section";
} else {
if (item.added) {
title = "added " + page.get('title');
}
if (item.changed) {
title = "changed " + page.get('title');
}
}
Ember.set(item, 'changeLabel', title);
let exists = sorted.findBy('item.pageId', item.pageId);
if (is.undefined(exists)) {
sorted.pushObject({ date: item.created, item: item });
}
});
this.set('sortedItems', _.sortBy(sorted, 'date').reverse());
});
}
});

View file

@ -14,17 +14,24 @@ import NotifierMixin from '../../mixins/notifier';
import TooltipMixin from '../../mixins/tooltip';
export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
documentService: Ember.inject.service('document'),
appMeta: Ember.inject.service(),
drop: null,
emptyState: Ember.computed.empty('files'),
deleteAttachment: {
id: "",
name: "",
},
emptyState: Ember.computed('files', function () {
return this.get('files.length') === 0;
}),
init() {
this._super(...arguments);
this.getAttachments();
},
didInsertElement() {
this._super(...arguments);
if (!this.get('isEditor')) {
return;
}
@ -54,7 +61,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
});
this.on("queuecomplete", function () {
self.attrs.onUpload();
self.getAttachments();
});
this.on("addedfile", function ( /*file*/ ) {
@ -71,15 +78,22 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
},
willDestroyElement() {
let drop = this.get('drop');
this._super(...arguments);
let drop = this.get('drop');
if (is.not.null(drop)) {
drop.destroy();
}
},
getAttachments() {
this.get('documentService').getAttachments(this.get('document.id')).then((files) => {
this.set('files', files);
});
},
actions: {
confirmDeleteAttachment(id, name) {
onConfirmDelete(id, name) {
this.set('deleteAttachment', {
id: id,
name: name
@ -103,7 +117,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
this.set('drop', drop);
},
cancel() {
onCancel() {
let drop = this.get('drop');
drop.close();
@ -113,16 +127,19 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
});
},
deleteAttachment() {
onDelete() {
let attachment = this.get('deleteAttachment');
let drop = this.get('drop');
drop.close();
this.attrs.onDelete(this.get('deleteAttachment').id, attachment.name);
this.showNotification(`Deleted ${name}`);
this.set('deleteAttachment', {
id: "",
name: ""
this.get('documentService').deleteAttachment(this.get('document.id'), attachment.id).then(() => {
this.getAttachments();
this.set('deleteAttachment', {
id: "",
name: ""
});
});
return true;

View file

@ -18,7 +18,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
document: {},
folder: {},
pages: [],
page: "",
currentPageId: "",
state: {
actionablePage: false,
upDisabled: true,
@ -31,13 +31,18 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
}),
didReceiveAttrs: function () {
this._super(...arguments);
this.set('showToc', is.not.undefined(this.get('pages')) && this.get('pages').get('length') > 0);
if (is.not.null(this.get('page'))) {
this.send('onEntryClick', this.get('page'));
if (is.not.null(this.get('currentPageId'))) {
this.send('onEntryClick', this.get('currentPageId'));
}
},
didRender: function () {
this._super(...arguments);
if (this.session.authenticated) {
this.addTooltip(document.getElementById("toc-up-button"));
this.addTooltip(document.getElementById("toc-down-button"));
@ -47,10 +52,14 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
},
didInsertElement() {
this._super(...arguments);
this.eventBus.subscribe('documentPageAdded', this, 'onDocumentPageAdded');
},
willDestroyElement() {
this._super(...arguments);
this.eventBus.unsubscribe('documentPageAdded');
this.destroyTooltips();
},
@ -62,7 +71,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
// Controls what user can do with the toc (left sidebar).
// Identifies the target pages.
setState(pageId) {
this.set('page', pageId);
this.set('currentPageId', pageId);
let toc = this.get('pages');
let page = _.findWhere(toc, { id: pageId });
@ -85,13 +94,13 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
let state = this.get('state');
let pages = this.get('pages');
let page = _.findWhere(pages, { id: this.get('page') });
let page = _.findWhere(pages, { id: this.get('currentPageId') });
let pendingChanges = tocUtil.moveUp(state, pages, page);
if (pendingChanges.length > 0) {
this.attrs.changePageSequence(pendingChanges);
this.attrs.onPageSequenceChange(pendingChanges);
this.send('onEntryClick', this.get('page'));
this.send('onEntryClick', this.get('currentPageId'));
this.audit.record("moved-page-up");
this.showNotification("Moved up");
}
@ -105,13 +114,13 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
let state = this.get('state');
var pages = this.get('pages');
var page = _.findWhere(pages, { id: this.get('page') });
var page = _.findWhere(pages, { id: this.get('currentPageId') });
let pendingChanges = tocUtil.moveDown(state, pages, page);
if (pendingChanges.length > 0) {
this.attrs.changePageSequence(pendingChanges);
this.attrs.onPageSequenceChange(pendingChanges);
this.send('onEntryClick', this.get('page'));
this.send('onEntryClick', this.get('currentPageId'));
this.audit.record("moved-page-down");
this.showNotification("Moved down");
}
@ -125,15 +134,15 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
let state = this.get('state');
var pages = this.get('pages');
var page = _.findWhere(pages, { id: this.get('page') });
var page = _.findWhere(pages, { id: this.get('currentPageId') });
let pendingChanges = tocUtil.indent(state, pages, page);
if (pendingChanges.length > 0) {
this.attrs.changePageLevel(pendingChanges);
this.attrs.onPageLevelChange(pendingChanges);
this.showNotification("Indent");
this.audit.record("changed-page-sequence");
this.send('onEntryClick', this.get('page'));
this.send('onEntryClick', this.get('currentPageId'));
}
},
@ -145,21 +154,21 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
let state = this.get('state');
var pages = this.get('pages');
var page = _.findWhere(pages, { id: this.get('page') });
var page = _.findWhere(pages, { id: this.get('currentPageId') });
let pendingChanges = tocUtil.outdent(state, pages, page);
if (pendingChanges.length > 0) {
this.attrs.changePageLevel(pendingChanges);
this.attrs.onPageLevelChange(pendingChanges);
this.showNotification("Outdent");
this.audit.record("changed-page-sequence");
this.send('onEntryClick', this.get('page'));
this.send('onEntryClick', this.get('currentPageId'));
}
},
onEntryClick(id) {
this.setState(id);
this.attrs.gotoPage(id);
this.attrs.onGotoPage(id);
}
}
});

View file

@ -10,114 +10,83 @@
// https://documize.com
import Ember from 'ember';
import NotifierMixin from '../../mixins/notifier';
import TooltipMixin from '../../mixins/tooltip';
import NotifierMixin from '../../mixins/notifier';
export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
export default Ember.Component.extend(TooltipMixin, NotifierMixin, {
documentService: Ember.inject.service('document'),
sectionService: Ember.inject.service('section'),
appMeta: Ember.inject.service(),
userService: Ember.inject.service('user'),
localStorage: Ember.inject.service(),
pinned: Ember.inject.service(),
drop: null,
users: [],
menuOpen: false,
saveTemplate: {
name: "",
description: ""
},
pinState : {
isPinned: false,
pinId: '',
newName: '',
},
didReceiveAttrs() {
this.set('saveTemplate.name', this.get('document.name'));
this.set('saveTemplate.description', this.get('document.excerpt'));
let doc = this.get('document');
this.set('layoutLabel', doc.get('layout') === 'doc' ? 'Wiki style' : 'Document style');
this.set('pinState.pinId', this.get('pinned').isDocumentPinned(doc.get('id')));
this.set('pinState.isPinned', this.get('pinState.pinId') !== '');
this.set('pinState.newName', doc.get('name').substring(0,3).toUpperCase());
saveTemplate: {
name: "",
description: ""
},
tab: '',
didRender() {
if (this.session.isEditor) {
this.addTooltip(document.getElementById("add-document-tab"));
init() {
this._super(...arguments);
if (is.empty(this.get('tab')) || is.undefined(this.get('tab'))) {
this.set('tab', 'index');
}
},
willDestroyElement() {
this.destroyTooltips();
didReceiveAttrs() {
this._super(...arguments);
this.set('saveTemplate.name', this.get('document.name'));
this.set('saveTemplate.description', this.get('document.excerpt'));
this.set('pinState.pinId', this.get('pinned').isDocumentPinned(this.get('document.id')));
this.set('pinState.isPinned', this.get('pinState.pinId') !== '');
this.set('pinState.newName', this.get('document.name').substring(0,3).toUpperCase());
},
actions: {
actions: {
onChangeTab(tab) {
this.set('tab', tab);
},
onTagChange(tags) {
let doc = this.get('document');
doc.set('tags', tags);
this.get('documentService').save(doc);
},
onMenuOpen() {
this.set('menuOpen', !this.get('menuOpen'));
},
deleteDocument() {
onDeleteDocument() {
this.attrs.onDocumentDelete();
},
printDocument() {
onPrintDocument() {
window.print();
},
changeLayout() {
let doc = this.get('document');
let layout = doc.get('layout') === 'doc' ? 'wiki' : 'doc';
onPageSequenceChange(changes) {
this.get('onPageSequenceChange')(changes);
},
doc.set('layout', layout);
onPageLevelChange(changes) {
this.get('onPageLevelChange')(changes);
},
this.attrs.onSaveMeta(doc);
onGotoPage(id) {
this.get('onGotoPage')(id);
},
this.set('layoutLabel', doc.get('layout') === 'doc' ? 'Wiki style' : 'Document style');
},
saveTemplate() {
var name = this.get('saveTemplate.name');
var excerpt = this.get('saveTemplate.description');
if (is.empty(name)) {
$("#new-template-name").addClass("error").focus();
return false;
}
if (is.empty(excerpt)) {
$("#new-template-desc").addClass("error").focus();
return false;
}
this.showNotification('Template saved');
this.attrs.onSaveTemplate(name, excerpt);
return true;
},
saveMeta() {
let doc = this.get('document');
if (is.empty(doc.get('name'))) {
$("#meta-name").addClass("error").focus();
return false;
}
if (is.empty(doc.get('excerpt'))) {
$("#meta-excerpt").addClass("error").focus();
return false;
}
doc.set('excerpt', doc.get('excerpt').substring(0, 250));
this.attrs.onSaveMeta(doc);
return true;
},
unpin() {
onUnpin() {
this.audit.record('unpinned-document');
this.get('pinned').unpinItem(this.get('pinState.pinId')).then(() => {
@ -127,7 +96,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
});
},
pin() {
onPin() {
let pin = {
pin: this.get('pinState.newName'),
documentId: this.get('document.id'),
@ -147,7 +116,27 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
this.eventBus.publish('pinChange');
});
return true;
},
onSaveTemplate() {
var name = this.get('saveTemplate.name');
var excerpt = this.get('saveTemplate.description');
if (is.empty(name)) {
$("#new-template-name").addClass("error").focus();
return false;
}
if (is.empty(excerpt)) {
$("#new-template-desc").addClass("error").focus();
return false;
}
this.showNotification('Template saved');
this.attrs.onSaveTemplate(name, excerpt);
return true;
}
}
}
});

View file

@ -0,0 +1,200 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import TooltipMixin from '../../mixins/tooltip';
const {
computed,
inject: { service }
} = Ember;
export default Ember.Component.extend(TooltipMixin, {
documentService: service('document'),
expanded: false,
deleteChildren: false,
menuOpen: false,
blockTitle: "",
blockExcerpt: "",
documentList: [], //includes the current document
documentListOthers: [], //excludes the current document
selectedDocument: null,
checkId: computed('page', function () {
let id = this.get('page.id');
return `delete-check-button-${id}`;
}),
menuTarget: computed('page', function () {
let id = this.get('page.id');
return `page-menu-${id}`;
}),
deleteButtonId: computed('page', function () {
let id = this.get('page.id');
return `delete-page-button-${id}`;
}),
publishButtonId: computed('page', function () {
let id = this.get('page.id');
return `publish-button-${id}`;
}),
publishDialogId: computed('page', function () {
let id = this.get('page.id');
return `publish-dialog-${id}`;
}),
blockTitleId: computed('page', function () {
let id = this.get('page.id');
return `block-title-${id}`;
}),
blockExcerptId: computed('page', function () {
let id = this.get('page.id');
return `block-excerpt-${id}`;
}),
copyButtonId: computed('page', function () {
let id = this.get('page.id');
return `copy-page-button-${id}`;
}),
copyDialogId: computed('page', function () {
let id = this.get('page.id');
return `copy-dialog-${id}`;
}),
moveButtonId: computed('page', function () {
let id = this.get('page.id');
return `move-page-button-${id}`;
}),
moveDialogId: computed('page', function () {
let id = this.get('page.id');
return `move-dialog-${id}`;
}),
didRender() {
$("#" + this.get('blockTitleId')).removeClass('error');
$("#" + this.get('blockExcerptId')).removeClass('error');
},
actions: {
toggleExpand() {
this.set('expanded', !this.get('expanded'));
this.get('onExpand')();
},
onMenuOpen() {
if ($('#' + this.get('publishDialogId')).is( ":visible" )) {
return;
}
if ($('#' + this.get('copyDialogId')).is( ":visible" )) {
return;
}
if ($('#' + this.get('moveDialogId')).is( ":visible" )) {
return;
}
this.set('menuOpen', !this.get('menuOpen'));
},
onEdit() {
this.attrs.onEdit();
},
deletePage() {
this.attrs.onDeletePage(this.get('deleteChildren'));
},
onSavePageAsBlock() {
let page = this.get('page');
let titleElem = '#' + this.get('blockTitleId');
let blockTitle = this.get('blockTitle');
if (is.empty(blockTitle)) {
$(titleElem).addClass('error');
return;
}
let excerptElem = '#' + this.get('blockExcerptId');
let blockExcerpt = this.get('blockExcerpt');
blockExcerpt = blockExcerpt.replace(/\n/g, "");
if (is.empty(blockExcerpt)) {
$(excerptElem).addClass('error');
return;
}
this.get('documentService').getPageMeta(this.get('document.id'), page.get('id')).then((pm) => {
let block = {
folderId: this.get('folder.id'),
contentType: page.get('contentType'),
pageType: page.get('pageType'),
title: blockTitle,
body: page.get('body'),
excerpt: blockExcerpt,
rawBody: pm.get('rawBody'),
config: pm.get('config'),
externalSource: pm.get('externalSource')
};
this.attrs.onSavePageAsBlock(block);
this.set('menuOpen', false);
this.set('blockTitle', '');
this.set('blockExcerpt', '');
$(titleElem).removeClass('error');
$(excerptElem).removeClass('error');
return true;
});
},
// Copy/move actions
onCopyDialogOpen() {
// Fetch document targets once.
if (this.get('documentList').length > 0) {
return;
}
this.get('documentService').getPageMoveCopyTargets().then((d) => {
let me = this.get('document');
this.set('documentList', d);
this.set('documentListOthers', d.filter((item) => item.get('id') !== me.get('id')));
});
},
onTargetChange(d) {
this.set('selectedDocument', d);
},
onCopyPage() {
// can't proceed if no data
if (this.get('documentList.length') === 0) {
return;
}
let targetDocumentId = this.get('document.id');
if (is.not.null(this.get('selectedDocument'))) {
targetDocumentId = this.get('selectedDocument.id');
}
this.attrs.onCopyPage(targetDocumentId);
return true;
},
onMovePage() {
// can't proceed if no data
if (this.get('documentListOthers.length') === 0) {
return;
}
if (is.null(this.get('selectedDocument'))) {
this.set('selectedDocument', this.get('documentListOthers')[0]);
}
let targetDocumentId = this.get('selectedDocument.id');
this.attrs.onMovePage(targetDocumentId);
return true;
}
}
});

View file

@ -10,7 +10,18 @@
// https://documize.com
import Ember from 'ember';
import NotifierMixin from '../../../mixins/notifier';
import NotifierMixin from '../../mixins/notifier';
export default Ember.Controller.extend(NotifierMixin, {
const {
inject: { service }
} = Ember;
export default Ember.Component.extend(NotifierMixin, {
appMeta :service(),
didRender() {
if (this.get('appMeta').invalidLicense()) {
this.showNotification(`!! Expired or invalid license !!`);
}
}
});

View file

@ -0,0 +1,129 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
const {
computed,
} = Ember;
export default Ember.Component.extend({
drop: null,
busy: false,
hasNameError: computed.empty('page.title'),
pageId: Ember.computed('page', function () {
let page = this.get('page');
return `page-editor-${page.id}`;
}),
cancelId: Ember.computed('page', function () {
let page = this.get('page');
return `cancel-edits-button-${page.id}`;
}),
dialogId: Ember.computed('page', function () {
let page = this.get('page');
return `discard-edits-dialog-${page.id}`;
}),
contentLinkerButtonId: Ember.computed('page', function () {
let page = this.get('page');
return `content-linker-button-${page.id}`;
}),
previewButtonId: Ember.computed('page', function () {
let page = this.get('page');
return `content-preview-button-${page.id}`;
}),
didRender() {
let self = this;
Mousetrap.bind('esc', function () {
self.send('onCancel');
return false;
});
Mousetrap.bind(['ctrl+s', 'command+s'], function () {
self.send('onAction');
return false;
});
$('#' + this.get('pageId')).focus(function() {
$(this).select();
});
},
willDestroyElement() {
let drop = this.get('drop');
if (is.not.null(drop)) {
drop.destroy();
}
Mousetrap.unbind('esc');
Mousetrap.unbind(['ctrl+s', 'command+s']);
},
actions: {
onCancel() {
if (this.attrs.isDirty() !== null && this.attrs.isDirty()) {
$('#' + this.get('dialogId')).css("display", "block");
let drop = new Drop({
target: $('#' + this.get('cancelId'))[0],
content: $('#' + this.get('dialogId'))[0],
classes: 'drop-theme-basic',
position: "bottom right",
openOn: "always",
constrainToWindow: true,
constrainToScrollParent: false,
tetherOptions: {
offset: "5px 0",
targetOffset: "10px 0"
},
remove: false
});
this.set('drop', drop);
return;
}
this.attrs.onCancel();
},
onAction() {
if (this.get('busy') || is.empty(this.get('page.title'))) {
return;
}
if (this.get('isDestroyed') || this.get('isDestroying')) {
return;
}
this.attrs.onAction(this.get('page.title'));
},
keepEditing() {
let drop = this.get('drop');
drop.close();
},
discardEdits() {
this.attrs.onCancel();
},
onInsertLink(selection) {
return this.get('onInsertLink')(selection);
},
onPreview() {
return this.get('onPreview')();
},
}
});

View file

@ -12,7 +12,4 @@
import Ember from 'ember';
export default Ember.Component.extend({
didReceiveAttrs() {
this.set('rendererType', 'section/' + this.get('page.contentType') + '/type-renderer');
},
});

View file

@ -15,9 +15,17 @@ import TooltipMixin from '../../../mixins/tooltip';
export default Ember.Component.extend(TooltipMixin, {
isDirty: false,
pageBody: "",
codeEditor: null,
syntaxOptions: [],
codeSyntax: null,
codeEditor: null,
editorId: Ember.computed('page', function () {
let page = this.get('page');
return `code-editor-${page.id}`;
}),
syntaxId: Ember.computed('page', function () {
let page = this.get('page');
return `code-editor-syntax-${page.id}`;
}),
init() {
this._super(...arguments);
@ -31,7 +39,7 @@ export default Ember.Component.extend(TooltipMixin, {
cleanBody = cleanBody.replace('<pre class="code-mirror cm-s-solarized cm-s-dark" data-lang="', "");
let startPos = cleanBody.indexOf('">');
let syntax = {
mode: "html",
mode: "htmlmixed",
name: "HTML"
};
@ -45,10 +53,7 @@ export default Ember.Component.extend(TooltipMixin, {
let opts = [];
_.each(_.sortBy(CodeMirror.modeInfo, 'name'), function(item) {
let i = {
mode: item.mode,
name: item.name
};
let i = { mode: item.mode, name: item.name };
opts.pushObject(i);
if (item.mode === syntax) {
@ -60,16 +65,12 @@ export default Ember.Component.extend(TooltipMixin, {
// default check
if (is.null(this.get("codeSyntax"))) {
this.set("codeSyntax", opts.findBy("mode", "html"));
this.set("codeSyntax", opts.findBy("mode", "htmlmixed"));
}
},
didRender() {
this.addTooltip(document.getElementById("set-syntax-zone"));
},
didInsertElement() {
var editor = CodeMirror.fromTextArea(document.getElementById("code-editor"), {
var editor = CodeMirror.fromTextArea(document.getElementById(this.get('editorId')), {
theme: "solarized dark",
lineNumbers: true,
lineWrapping: true,
@ -79,12 +80,13 @@ export default Ember.Component.extend(TooltipMixin, {
dragDrop: false
});
editor.setSize("100%", $(document).height() - $(".document-editor > .toolbar").height() - 180);
CodeMirror.commands.save = function(/*instance*/){
Mousetrap.trigger('ctrl+s');
};
this.set('codeEditor', editor);
let syntax = this.get("codeSyntax");
if (is.not.undefined(syntax)) {
CodeMirror.autoLoadMode(editor, syntax.mode);
editor.setOption("mode", syntax.mode);
@ -92,7 +94,6 @@ export default Ember.Component.extend(TooltipMixin, {
},
willDestroyElement() {
this.destroyTooltips();
this.set('codeEditor', null);
},
@ -115,7 +116,7 @@ export default Ember.Component.extend(TooltipMixin, {
},
isDirty() {
return this.get('isDirty');
return this.get('isDirty') || (this.get('codeEditor').getDoc().isClean() === false);
},
onCancel() {

View file

@ -16,6 +16,11 @@ export default Ember.Component.extend({
codeSyntax: "htmlmixed",
didReceiveAttrs() {
this._super(...arguments);
if (this.get('isDestroyed') || this.get('isDestroying')) {
return;
}
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
let page = this.get('page');
@ -27,9 +32,22 @@ export default Ember.Component.extend({
this.set('codeSyntax', cleanBody.substring(0, startPos));
this.set('codeBody', cleanBody.substring(startPos + 2));
}
_.each(_.sortBy(CodeMirror.modeInfo, 'name'), (item) => {
let i = { mode: item.mode, name: item.name };
if (item.mode === this.get('codeSyntax')) {
this.set('codeSyntax', i);
}
});
},
didRender() {
didInsertElement() {
this._super(...arguments);
if (this.get('isDestroyed') || this.get('isDestroying')) {
return;
}
let page = this.get('page');
let elem = `page-${page.id}-code`;
@ -44,14 +62,18 @@ export default Ember.Component.extend({
readOnly: true
});
let syntax = this.get("codeSyntax");
CodeMirror.autoLoadMode(editor, syntax);
editor.setOption("mode", syntax);
this.set('codeEditor', editor);
let syntax = this.get("codeSyntax");
if (is.not.undefined(syntax)) {
CodeMirror.autoLoadMode(editor, syntax.mode);
editor.setOption("mode", syntax.mode);
}
},
willDestroyElement() {
this._super(...arguments);
this.set('codeEditor', null);
}
});

View file

@ -110,11 +110,16 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
this.get('sectionService').fetch(page, "items", this.get('config'))
.then(function (response) {
// console.log(response);
if (self.get('isDestroyed') || self.get('isDestroying')) {
return;
}
self.set('items', response);
self.set('config.itemCount', response.length);
self.set('waiting', false);
}, function (reason) { //jshint ignore: line
if (self.get('isDestroyed') || self.get('isDestroying')) {
return;
}
self.set('items', []);
self.set('waiting', false);
});

View file

@ -10,68 +10,141 @@
// https://documize.com
import Ember from 'ember';
import miscUtil from '../../../utils/misc';
import TooltipMixin from '../../../mixins/tooltip';
const {
inject: { service }
} = Ember;
export default Ember.Component.extend({
export default Ember.Component.extend(TooltipMixin, {
link: service(),
editMode: true,
isDirty: false,
pageBody: "",
pagePreview: "",
height: $(document).height() - 450,
editMode: true,
codeSyntax: null,
codeEditor: null,
editorId: Ember.computed('page', function () {
let page = this.get('page');
return `markdown-editor-${page.id}`;
}),
previewId: Ember.computed('page', function () {
let page = this.get('page');
return `markdown-preview-${page.id}`;
}),
didReceiveAttrs() {
this.set("pageBody", this.get("meta.rawBody"));
},
init() {
this._super(...arguments);
let self = this;
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
let rawBody = this.get('meta.rawBody');
let cleanBody = rawBody.replace("</pre>", "");
cleanBody = cleanBody.replace('<pre class="code-mirror cm-s-solarized cm-s-dark" data-lang="', "");
let startPos = cleanBody.indexOf('">');
let syntax = {
mode: "markdown",
name: "Markdown"
};
if (startPos !== -1) {
syntax = cleanBody.substring(0, startPos);
cleanBody = cleanBody.substring(startPos + 2);
}
this.set('pageBody', cleanBody);
let opts = [];
_.each(_.sortBy(CodeMirror.modeInfo, 'name'), function(item) {
let i = {
mode: item.mode,
name: item.name
};
opts.pushObject(i);
if (item.mode === syntax) {
self.set('codeSyntax', i);
}
});
this.set('syntaxOptions', opts);
// default check
if (is.null(this.get("codeSyntax"))) {
this.set("codeSyntax", opts.findBy("mode", "markdown"));
}
},
didInsertElement() {
$("#section-markdown-editor").css("height", this.get('height'));
$("#section-markdown-preview").css("height", this.get('height'));
this.attachEditor();
},
$("#section-markdown-editor").off("keyup").on("keyup", () => {
this.set('isDirty', true);
});
willDestroyElement() {
this.set('codeEditor', null);
this.destroyTooltips();
},
getBody() {
return this.get('codeEditor').getDoc().getValue();
},
willDestroyElement() {
$("#section-markdown-editor").off("keyup");
didRender() {
this.addTooltip(document.getElementById(this.get('tooltipId')));
},
attachEditor() {
var editor = CodeMirror.fromTextArea(document.getElementById(this.get('editorId')), {
theme: "solarized light",
lineNumbers: true,
lineWrapping: true,
indentUnit: 4,
tabSize: 4,
value: "",
dragDrop: false,
extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}
});
CodeMirror.commands.save = function(/*instance*/){
Mousetrap.trigger('ctrl+s');
};
this.set('codeEditor', editor);
let syntax = this.get("codeSyntax");
if (is.not.undefined(syntax)) {
CodeMirror.autoLoadMode(editor, syntax.mode);
editor.setOption("mode", syntax.mode);
}
},
actions: {
toggleMode() {
onPreview() {
this.set('editMode', !this.get('editMode'));
Ember.run.schedule('afterRender', () => {
if (this.get('editMode')) {
$("#section-markdown-editor").off("keyup").on("keyup", () => {
this.set('isDirty', true);
});
$("#section-markdown-editor").css("height", this.get('height'));
this.attachEditor();
} else {
let md = window.markdownit({ linkify: true });
let result = md.render(this.get("pageBody"));
let result = md.render(this.getBody());
this.set('pagePreview', result);
$("#section-markdown-preview").css("height", this.get('height'));
}
});
},
onInsertLink(link) {
let linkMarkdown = this.get('link').buildLink(link);
miscUtil.insertAtCursor($("#section-markdown-editor")[0], linkMarkdown);
this.set('pageBody', $("#section-markdown-editor").val());
this.get('codeEditor').getDoc().replaceSelection(linkMarkdown);
return true;
},
isDirty() {
return this.get('isDirty');
return this.get('codeEditor').getDoc().isClean() === false;
},
onCancel() {
@ -82,7 +155,7 @@ export default Ember.Component.extend({
let page = this.get('page');
let meta = this.get('meta');
page.set('title', title);
meta.set('rawBody', this.get("pageBody"));
meta.set('rawBody', this.getBody());
this.attrs.onAction(page, meta);
}

View file

@ -74,7 +74,6 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
self.set('authenticated', true);
self.set('items', response);
self.set('config.APIToken', '********'); // reset the api token once it has been sent to the host
console.log("auth token OK");
self.get('sectionService').fetch(page, "options", config)
.then(function (response) {

View file

@ -14,6 +14,10 @@ import Ember from 'ember';
export default Ember.Component.extend({
isDirty: false,
pageBody: "",
editorId: Ember.computed('page', function () {
let page = this.get('page');
return `table-editor-${page.id}`;
}),
defaultTable: '<table class="wysiwyg-table" style="width: 100%;"><thead><tr><th><br></th><th><br></th><th><br></th><th><br></th></tr></thead><tbody><tr><td style="width: 25.0000%;"><br></td><td style="width: 25.0000%;"><br></td><td style="width: 25.0000%;"><br></td><td style="width: 25.0000%;"><br></td></tr><tr><td style="width: 25.0000%;"><br></td><td style="width: 25.0000%;"><br></td><td style="width: 25.0000%;"><br></td><td style="width: 25.0000%;"><br></td></tr><tr><td style="width: 25.0000%;"><br></td><td style="width: 25.0000%;"><br></td><td style="width: 25.0000%;"><br></td><td style="width: 25.0000%;"><br></td></tr></tbody></table>',
didReceiveAttrs() {
@ -25,23 +29,20 @@ export default Ember.Component.extend({
},
didInsertElement() {
$('#table-editor').froalaEditor({
let id = '#' + this.get('editorId');
$(id).froalaEditor({
toolbarButtons: [],
height: $(document).height() - 400,
toolbarInline: true,
tableResizerOffset: 10
});
$('#table-editor').on('froalaEditor.contentChanged', () => {
$(id).on('froalaEditor.contentChanged', () => {
this.set('isDirty', true);
});
},
willDestroyElement() {
$('#table-editor').off('froalaEditor.contentChanged');
// if ($('#table-editor').data('froala.editor')) {
// $('#table-editor').froalaEditor('destroy');
// }
$('#' + this.get('editorId')).off('froalaEditor.contentChanged');
},
actions: {
@ -57,7 +58,7 @@ export default Ember.Component.extend({
let page = this.get('page');
let meta = this.get('meta');
let body = $("#table-editor").froalaEditor('html.get', true);
let body = $('#' + this.get('editorId')).froalaEditor('html.get', true);
page.set('title', title);
if (is.empty(body)) {

View file

@ -19,29 +19,32 @@ export default Ember.Component.extend({
appMeta: service(),
link: service(),
pageBody: "",
editorId: Ember.computed('page', function () {
let page = this.get('page');
return `wysiwyg-editor-${page.id}`;
}),
didReceiveAttrs() {
this.set('pageBody', this.get('meta.rawBody'));
},
didInsertElement() {
let maxHeight = $(document).height() - 450;
let options = {
selector: "#rich-text-editor",
selector: "#" + this.get('editorId'),
relative_urls: false,
cache_suffix: "?v=443",
browser_spellcheck: false,
gecko_spellcheck: false,
theme: "modern",
skin: 'documize',
statusbar: false,
height: maxHeight,
inline: true,
entity_encoding: "raw",
paste_data_images: true,
image_advtab: true,
image_caption: true,
media_live_embeds: true,
fontsize_formats: "8px 10px 12px 14px 18px 24px 36px 40px 50px 60px",
fontsize_formats: "8px 10px 12px 14px 17px 18px 24px 36px 40px 50px 60px",
formats: {
bold: {
inline: 'b'
@ -50,6 +53,17 @@ export default Ember.Component.extend({
inline: 'i'
}
},
codesample_languages: [
{text: 'HTML/XML', value: 'markup'},
{text: 'JavaScript', value: 'javascript'},
{text: 'CSS', value: 'css'},
{text: 'PHP', value: 'php'},
{text: 'Ruby', value: 'ruby'},
{text: 'Python', value: 'python'},
{text: 'Java', value: 'java'},
{text: 'C', value: 'c'},
{text: 'C#', value: 'csharp'},
{text: 'C++', value: 'cpp'}],
extended_valid_elements: "b,i,b/strong,i/em",
plugins: [
'advlist autolink lists link image charmap print preview hr anchor pagebreak',
@ -59,8 +73,8 @@ export default Ember.Component.extend({
],
menu: {},
menubar: false,
toolbar1: "bold italic underline strikethrough superscript subscript | outdent indent bullist numlist forecolor backcolor | alignleft aligncenter alignright alignjustify | link unlink | table image media codesample",
toolbar2: "formatselect fontselect fontsizeselect",
toolbar1: "formatselect fontsizeselect | bold italic underline strikethrough superscript subscript | forecolor backcolor link unlink",
toolbar2: "outdent indent bullist numlist | alignleft aligncenter alignright alignjustify | table image media codesample",
save_onsavecallback: function () {
Mousetrap.trigger('ctrl+s');
}
@ -79,25 +93,27 @@ export default Ember.Component.extend({
},
willDestroyElement() {
tinymce.remove();
tinymce.EditorManager.execCommand('mceRemoveEditor', true, this.get('editorId'));
},
actions: {
onInsertLink(link) {
let userSelection = tinymce.activeEditor.selection.getContent();
let editor = tinymce.EditorManager.get(this.get('editorId'));
let userSelection = editor.selection.getContent();
if (is.not.empty(userSelection)) {
Ember.set(link, 'title', userSelection);
}
let linkHTML = this.get('link').buildLink(link);
tinymce.activeEditor.insertContent(linkHTML);
editor.insertContent(linkHTML);
return true;
},
isDirty() {
return is.not.undefined(tinymce) && is.not.undefined(tinymce.activeEditor) && tinymce.activeEditor.isDirty();
let editor = tinymce.EditorManager.get(this.get('editorId'));
return is.not.undefined(tinymce) && is.not.undefined(editor) && editor.isDirty();
},
onCancel() {
@ -107,9 +123,10 @@ export default Ember.Component.extend({
onAction(title) {
let page = this.get('page');
let meta = this.get('meta');
let editor = tinymce.EditorManager.get(this.get('editorId'));
page.set('title', title);
meta.set('rawBody', tinymce.activeEditor.getContent());
meta.set('rawBody', editor.getContent());
this.attrs.onAction(page, meta);
}

View file

@ -1,6 +1,5 @@
<!DOCTYPE html>
<html>
<head>
{{content-for 'head'}}
<meta charset="utf-8">
@ -17,7 +16,6 @@
<link rel="stylesheet" href="/assets/documize.css">
{{content-for 'head-footer'}}
</head>
<body>
{{content-for 'body'}}
<script src="/assets/vendor.js"></script>
@ -29,5 +27,4 @@
<script src="/codemirror/addon/runmode/colorize.js"></script>
{{content-for 'body-footer'}}
</body>
</html>

View file

@ -25,7 +25,6 @@ export default Model.extend({
userId: attr('string'),
tags: attr('string'),
template: attr('boolean'),
layout: attr('string'),
// client-side property
selected: attr('boolean', { defaultValue: false }),

View file

@ -29,7 +29,8 @@ export default Model.extend({
meta: attr(),
tagName: Ember.computed('level', function () {
return "h" + (this.get('level') + 1);
return "h2";
// return "h" + (this.get('level') + 1);
}),
tocIndent: Ember.computed('level', function () {

View file

@ -1,33 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
documentService: Ember.inject.service('document'),
model() {
this.audit.record("viewed-document-activity");
return Ember.RSVP.hash({
folders: this.modelFor('document').folders,
folder: this.modelFor('document').folder,
document: this.modelFor('document').document,
isEditor: this.modelFor('document').isEditor,
pages: this.modelFor('document').allPages,
tabs: this.modelFor('document').tabs,
activity: this.get('documentService').getMeta(this.modelFor('document').document.get('id')).then((activity) => {
return activity;
})
});
}
});

View file

@ -1 +0,0 @@
{{document/document-activity document=model.document pages=model.pages activity=model.activity}}

View file

@ -16,31 +16,23 @@ export default Ember.Controller.extend({
actions: {
onCancel( /*page*/ ) {
this.transitionToRoute('document', {
queryParams: {
page: this.get('model.page.id')
}
});
this.transitionToRoute('document');
},
onAction(page, meta) {
let self = this;
let block = this.get('model.block');
block.set('title', page.get('title'));
block.set('body', page.get('body'));
block.set('excerpt', page.get('excerpt'));
block.set('rawBody', meta.get('rawBody'));
block.set('config', meta.get('config'));
block.set('externalSource', meta.get('externalSource'));
let b = this.get('model.block');
b.set('title', page.get('title'));
b.set('body', page.get('body'));
b.set('excerpt', page.get('excerpt'));
b.set('rawBody', meta.get('rawBody'));
b.set('config', meta.get('config'));
b.set('externalSource', meta.get('externalSource'));
this.get('sectionService').updateBlock(block).then(function () {
this.get('sectionService').updateBlock(b).then(function () {
self.audit.record("edited-block");
self.transitionToRoute('document', {
queryParams: {
page: page.get('id')
}
});
self.transitionToRoute('document');
});
}
}

View file

@ -27,5 +27,13 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
document: self.modelFor('document').document,
block: self.get('sectionService').getBlock(params.block_id),
});
}
},
activate() {
$('body').addClass('background-color-off-white');
},
deactivate() {
$('body').removeClass('background-color-off-white');
}
});

View file

@ -1 +1,20 @@
{{document/block-editor document=model.document folder=model.folder block=model.block onCancel=(action 'onCancel') onAction=(action 'onAction')}}
<div class="zone-section-editor">
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div id="zone-document-content" class="zone-document-content">
<div class="back-to-space">
{{#link-to 'document.index' model.folder.id model.folder.slug model.document.id model.document.slug}}
<i class="material-icons">arrow_back</i>&nbsp;{{model.document.name}}
{{/link-to}}
</div>
{{document/document-heading document=model.document isEditor=false}}
{{document/block-editor document=model.document folder=model.folder block=model.block onCancel=(action 'onCancel') onAction=(action 'onAction')}}
</div>
</div>
</div>
</div>
</div>

View file

@ -13,196 +13,4 @@ import Ember from 'ember';
import NotifierMixin from '../../mixins/notifier';
export default Ember.Controller.extend(NotifierMixin, {
documentService: Ember.inject.service('document'),
templateService: Ember.inject.service('template'),
sectionService: Ember.inject.service('section'),
page: null,
folder: {},
pages: [],
// Jump to the right part of the document.
scrollToPage(pageId) {
Ember.run.schedule('afterRender', function () {
let dest;
let target = "#page-title-" + pageId;
let targetOffset = $(target).offset();
if (is.undefined(targetOffset)) {
return;
}
dest = targetOffset.top > $(document).height() - $(window).height() ? $(document).height() - $(window).height() : targetOffset.top;
// small correction to ensure we also show page title
dest = dest > 50 ? dest - 74 : dest;
$("html,body").animate({
scrollTop: dest
}, 500, "linear");
$(".toc-index-item").removeClass("selected");
$("#index-" + pageId).addClass("selected");
});
},
actions: {
gotoPage(pageId) {
if (is.null(pageId)) {
return;
}
this.scrollToPage(pageId);
},
onPageSequenceChange(changes) {
this.get('documentService').changePageSequence(this.get('model.document.id'), changes).then(() => {
_.each(changes, (change) => {
let pageContent = _.findWhere(this.get('model.pages'), {
id: change.pageId
});
if (is.not.undefined(pageContent)) {
pageContent.set('sequence', change.sequence);
}
});
this.set('model.pages', this.get('model.pages').sortBy('sequence'));
this.get('target.router').refresh();
});
},
onPageLevelChange(changes) {
this.get('documentService').changePageLevel(this.get('model.document.id'), changes).then(() => {
_.each(changes, (change) => {
let pageContent = _.findWhere(this.get('model.pages'), {
id: change.pageId
});
if (is.not.undefined(pageContent)) {
pageContent.set('level', change.level);
}
});
let pages = this.get('model.pages');
pages = pages.sortBy('sequence');
this.set('model.pages', []);
this.set('model.pages', pages);
this.get('target.router').refresh();
});
},
onSaveTemplate(name, desc) {
this.get('templateService').saveAsTemplate(this.get('model.document.id'), name, desc).then(function () {});
},
onSaveMeta(doc) {
this.get('documentService').save(doc).then(() => {
this.transitionToRoute('document.index');
});
},
onAddSection(section) {
this.audit.record("added-section-" + section.get('contentType'));
let page = {
documentId: this.get('model.document.id'),
title: `${section.get('title')}`,
level: 1,
sequence: 0,
body: "",
contentType: section.get('contentType'),
pageType: section.get('pageType')
};
let meta = {
documentId: this.get('model.document.id'),
rawBody: "",
config: ""
};
let model = {
page: page,
meta: meta
};
this.get('documentService').addPage(this.get('model.document.id'), model).then((newPage) => {
let data = this.get('store').normalize('page', newPage);
this.get('store').push(data);
this.get('documentService').getPages(this.get('model.document.id')).then((pages) => {
this.set('model.pages', pages.filterBy('pageType', 'section'));
this.set('model.tabs', pages.filterBy('pageType', 'tab'));
this.get('documentService').getPageMeta(this.get('model.document.id'), newPage.id).then(() => {
this.transitionToRoute('document.edit',
this.get('model.folder.id'),
this.get('model.folder.slug'),
this.get('model.document.id'),
this.get('model.document.slug'),
newPage.id);
});
});
});
},
onInsertBlock(block) {
this.audit.record("added-content-block-" + block.get('contentType'));
let page = {
documentId: this.get('model.document.id'),
title: `${block.get('title')}`,
level: 1,
sequence: 0,
body: block.get('body'),
contentType: block.get('contentType'),
pageType: block.get('pageType'),
blockId: block.get('id')
};
let meta = {
documentId: this.get('model.document.id'),
rawBody: block.get('rawBody'),
config: block.get('config'),
externalSource: block.get('externalSource')
};
let model = {
page: page,
meta: meta
};
this.get('documentService').addPage(this.get('model.document.id'), model).then((newPage) => {
let data = this.get('store').normalize('page', newPage);
this.get('store').push(data);
this.get('documentService').getPages(this.get('model.document.id')).then((pages) => {
this.set('model.pages', pages.filterBy('pageType', 'section'));
this.set('model.tabs', pages.filterBy('pageType', 'tab'));
this.get('documentService').getPageMeta(this.get('model.document.id'), newPage.id).then(() => {
this.transitionToRoute('document.edit',
this.get('model.folder.id'),
this.get('model.folder.slug'),
this.get('model.document.id'),
this.get('model.document.slug'),
newPage.id);
});
});
});
},
onDeleteBlock(blockId) {
this.get('sectionService').deleteBlock(blockId).then(() => {
this.audit.record("deleted-block");
this.send("showNotification", "Deleted");
this.transitionToRoute('document.index');
});
},
onDocumentDelete() {
this.get('documentService').deleteDocument(this.get('model.document.id')).then(() => {
this.audit.record("deleted-page");
this.send("showNotification", "Deleted");
this.transitionToRoute('folder', this.get('model.folder.id'), this.get('model.folder.slug'));
});
}
}
});

View file

@ -1,43 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
export default Ember.Controller.extend({
documentService: Ember.inject.service('document'),
actions: {
onCancel( /*page*/ ) {
this.transitionToRoute('document', {
queryParams: {
page: this.get('model.page.id')
}
});
},
onAction(page, meta) {
let self = this;
let model = {
page: page.toJSON({ includeId: true }),
meta: meta.toJSON({ includeId: true })
};
this.get('documentService').updatePage(page.get('documentId'), page.get('id'), model).then(function () {
self.audit.record("edited-page");
self.transitionToRoute('document', {
queryParams: {
page: page.get('id')
}
});
});
}
}
});

View file

@ -1,31 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
documentService: Ember.inject.service('document'),
folderService: Ember.inject.service('folder'),
model(params) {
let self = this;
this.audit.record("edited-page");
return Ember.RSVP.hash({
folder: self.modelFor('document').folder,
document: self.modelFor('document').document,
page: self.get('documentService').getPage(self.paramsFor('document').document_id, params.page_id),
meta: self.get('documentService').getPageMeta(self.paramsFor('document').document_id, params.page_id)
});
}
});

View file

@ -1 +0,0 @@
{{document/document-editor document=model.document folder=model.folder page=model.page meta=model.meta onCancel=(action 'onCancel') onAction=(action 'onAction')}}

View file

@ -1,40 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import NotifierMixin from '../../../mixins/notifier';
export default Ember.Controller.extend(NotifierMixin, {
documentService: Ember.inject.service('document'),
getAttachments() {
let self = this;
this.get('documentService').getAttachments(this.get('model.document.id')).then(function (files) {
self.set('model.files', files);
});
},
actions: {
onUpload() {
this.getAttachments();
},
onDelete(id, name) {
let self = this;
this.showNotification(`Deleted ${name}`);
this.get('documentService').deleteAttachment(this.get('model.document.id'), id).then(function () {
self.getAttachments();
});
},
}
});

View file

@ -1,31 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
documentService: Ember.inject.service('document'),
model() {
this.audit.record("viewed-document-attachments");
return Ember.RSVP.hash({
folders: this.modelFor('document').folders,
folder: this.modelFor('document').folder,
document: this.modelFor('document').document,
isEditor: this.modelFor('document').isEditor,
pages: this.modelFor('document').allPages,
tabs: this.modelFor('document').tabs,
files: this.get('documentService').getAttachments(this.modelFor('document').document.get('id'))
});
}
});

View file

@ -1 +0,0 @@
{{document/document-files document=model.document files=model.files isEditor=model.isEditor onUpload=(action 'onUpload') onDelete=(action 'onDelete')}}

View file

@ -17,11 +17,11 @@ export default Ember.Controller.extend(NotifierMixin, {
this.audit.record("restored-page");
this.get('documentService').rollbackPage(this.get('model.document.id'), pageId, revisionId).then(() => {
this.transitionToRoute('document', {
queryParams: {
page: pageId
}
});
this.transitionToRoute('document.index',
this.get('model.folder.id'),
this.get('model.folder.slug'),
this.get('model.document.id'),
this.get('model.document.slug'));
});
}
}

View file

@ -1,2 +1,21 @@
{{document/document-history document=model.document folder=model.folder pages=model.pages revisions=model.revisions diff=model.diff
onFetchDiff=(action 'onFetchDiff') onRollback=(action 'onRollback')}}
<div class="zone-document-history">
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div id="zone-document-content" class="zone-document-content">
<div class="back-to-space">
{{#link-to 'document.index' model.folder.id model.folder.slug model.document.id model.document.slug}}
<i class="material-icons">arrow_back</i>&nbsp;{{model.document.name}}
{{/link-to}}
</div>
{{document/document-heading document=model.document isEditor=false}}
{{document/document-history document=model.document folder=model.folder pages=model.pages
revisions=model.revisions diff=model.diff onFetchDiff=(action 'onFetchDiff') onRollback=(action 'onRollback')}}
</div>
</div>
</div>
</div>
</div>

View file

@ -14,39 +14,176 @@ import NotifierMixin from '../../../mixins/notifier';
export default Ember.Controller.extend(NotifierMixin, {
documentService: Ember.inject.service('document'),
templateService: Ember.inject.service('template'),
sectionService: Ember.inject.service('section'),
queryParams: ['page'],
// Jump to the right part of the document.
scrollToPage(pageId) {
Ember.run.schedule('afterRender', function () {
let dest;
let target = "#page-title-" + pageId;
let targetOffset = $(target).offset();
if (is.undefined(targetOffset)) {
return;
}
dest = targetOffset.top > $(document).height() - $(window).height() ? $(document).height() - $(window).height() : targetOffset.top;
// small correction to ensure we also show page title
dest = dest > 50 ? dest - 74 : dest;
$("html,body").animate({
scrollTop: dest
}, 500, "linear");
$(".toc-index-item").removeClass("selected");
$("#index-" + pageId).addClass("selected");
});
},
folder: {},
pages: [],
toggled: false,
queryParams: ['pageId', 'tab'],
pageId: '',
tab: 'index',
actions: {
gotoPage(pageId) {
if (is.null(pageId)) {
return;
toggleSidebar() {
this.set('toggled', !this.get('toggled'));
},
onSaveDocument(doc) {
this.get('documentService').save(doc);
this.showNotification('Saved');
},
onCopyPage(pageId, targetDocumentId) {
let documentId = this.get('model.document.id');
this.get('documentService').copyPage(documentId, pageId, targetDocumentId).then(() => {
this.showNotification("Copied");
// refresh data if copied to same document
if (documentId === targetDocumentId) {
this.set('pageId', '');
this.get('target.router').refresh();
}
});
},
onMovePage(pageId, targetDocumentId) {
let documentId = this.get('model.document.id');
this.get('documentService').copyPage(documentId, pageId, targetDocumentId).then(() => {
this.showNotification("Moved");
this.send('onPageDeleted', { id: pageId, children: false });
});
},
onSavePage(page, meta) {
let documentId = this.get('model.document.id');
let model = {
page: page.toJSON({ includeId: true }),
meta: meta.toJSON({ includeId: true })
};
this.get('documentService').updatePage(documentId, page.get('id'), model).then(() => {
this.set('pageId', page.get('id'));
});
this.audit.record("edited-page");
},
onPageDeleted(deletePage) {
let documentId = this.get('model.document.id');
let pages = this.get('model.pages');
let deleteId = deletePage.id;
let deleteChildren = deletePage.children;
let page = _.findWhere(pages, {
id: deleteId
});
let pageIndex = _.indexOf(pages, page, false);
let pendingChanges = [];
this.audit.record("deleted-page");
// select affected pages
for (var i = pageIndex + 1; i < pages.get('length'); i++) {
if (pages[i].get('level') <= page.get('level')) {
break;
}
pendingChanges.push({
pageId: pages[i].get('id'),
level: pages[i].get('level') - 1
});
}
this.scrollToPage(pageId);
this.set('pageId', '');
if (deleteChildren) {
// nuke of page tree
pendingChanges.push({
pageId: deleteId
});
this.get('documentService').deletePages(documentId, deleteId, pendingChanges).then(() => {
// update our models so we don't have to reload from db
for (var i = 0; i < pendingChanges.length; i++) {
let pageId = pendingChanges[i].pageId;
this.set('model.pages', _.reject(pages, function (p) { //jshint ignore: line
return p.get('id') === pageId;
}));
}
this.set('model.pages', _.sortBy(pages, "sequence"));
this.transitionToRoute('document.index',
this.get('model.folder.id'),
this.get('model.folder.slug'),
this.get('model.document.id'),
this.get('model.document.slug'));
});
} else {
// page delete followed by re-leveling child pages
this.get('documentService').deletePage(documentId, deleteId).then(() => {
this.set('model.pages', _.reject(pages, function (p) {
return p.get('id') === deleteId;
}));
this.send('onPageLevelChange', pendingChanges);
});
}
},
onInsertSection(data) {
return new Ember.RSVP.Promise((resolve) => {
this.get('documentService').addPage(this.get('model.document.id'), data).then((newPage) => {
let data = this.get('store').normalize('page', newPage);
this.get('store').push(data);
this.set('pageId', newPage.id);
this.get('documentService').getPages(this.get('model.document.id')).then((pages) => {
this.set('model.pages', pages);
if (newPage.pageType === 'tab') {
this.transitionToRoute('document.section',
this.get('model.folder.id'),
this.get('model.folder.slug'),
this.get('model.document.id'),
this.get('model.document.slug'),
newPage.id);
} else {
resolve(newPage.id);
}
});
});
});
},
onDeleteBlock(blockId) {
return new Ember.RSVP.Promise((resolve) => {
this.get('sectionService').deleteBlock(blockId).then(() => {
this.audit.record("deleted-block");
this.send("showNotification", "Deleted");
resolve();
});
});
},
onSavePageAsBlock(block) {
return new Ember.RSVP.Promise((resolve) => {
this.get('sectionService').addBlock(block).then(() => {
this.showNotification("Published");
resolve();
});
});
},
onDocumentDelete() {
this.get('documentService').deleteDocument(this.get('model.document.id')).then(() => {
this.audit.record("deleted-page");
this.send("showNotification", "Deleted");
this.transitionToRoute('folder', this.get('model.folder.id'), this.get('model.folder.slug'));
});
},
onSaveTemplate(name, desc) {
this.get('templateService').saveAsTemplate(this.get('model.document.id'), name, desc).then(function () {});
},
onPageSequenceChange(changes) {
@ -80,92 +217,15 @@ export default Ember.Controller.extend(NotifierMixin, {
let pages = this.get('model.pages');
pages = pages.sortBy('sequence');
this.set('model.pages', []);
this.set('model.pages', pages);
this.get('target.router').refresh();
});
},
onAddBlock(block) {
this.get('sectionService').addBlock(block).then(() => {
this.showNotification("Published");
});
},
onCopyPage(pageId, targetDocumentId) {
let documentId = this.get('model.document.id');
this.get('documentService').copyPage(documentId, pageId, targetDocumentId).then(() => {
this.showNotification("Copied");
// refresh data if copied to same document
if (documentId === targetDocumentId) {
this.get('target.router').refresh();
}
});
},
onMovePage(pageId, targetDocumentId) {
let documentId = this.get('model.document.id');
this.get('documentService').copyPage(documentId, pageId, targetDocumentId).then(() => {
this.showNotification("Moved");
this.send('onPageDeleted', { id: pageId, children: false });
});
},
onPageDeleted(deletePage) {
let documentId = this.get('model.document.id');
let pages = this.get('model.pages');
let deleteId = deletePage.id;
let deleteChildren = deletePage.children;
let page = _.findWhere(pages, {
id: deleteId
});
let pageIndex = _.indexOf(pages, page, false);
let pendingChanges = [];
this.audit.record("deleted-page");
// select affected pages
for (var i = pageIndex + 1; i < pages.get('length'); i++) {
if (pages[i].get('level') <= page.get('level')) {
break;
}
pendingChanges.push({
pageId: pages[i].get('id'),
level: pages[i].get('level') - 1
});
}
if (deleteChildren) {
// nuke of page tree
pendingChanges.push({
pageId: deleteId
});
this.get('documentService').deletePages(documentId, deleteId, pendingChanges).then(() => {
// update our models so we don't have to reload from db
for (var i = 0; i < pendingChanges.length; i++) {
let pageId = pendingChanges[i].pageId;
this.set('model.pages', _.reject(pages, function (p) { //jshint ignore: line
return p.get('id') === pageId;
}));
}
this.set('model.pages', _.sortBy(pages, "sequence"));
this.get('target.router').refresh();
});
} else {
// page delete followed by re-leveling child pages
this.get('documentService').deletePage(documentId, deleteId).then(() => {
this.set('model.pages', _.reject(pages, function (p) {
return p.get('id') === deleteId;
}));
this.send('onPageLevelChange', pendingChanges);
});
onGotoPage(id) {
if (this.get('pageId') !== id && id !== '') {
this.set('pageId', id);
}
}
}

View file

@ -17,50 +17,20 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
linkService: Ember.inject.service('link'),
folderService: Ember.inject.service('folder'),
userService: Ember.inject.service('user'),
queryParams: {
page: {
refreshModel: false
}
},
beforeModel(transition) {
this.set('pageId', is.not.undefined(transition.queryParams.page) ? transition.queryParams.page : "");
this.set('folderId', this.paramsFor('document').folder_id);
this.set('documentId', this.paramsFor('document').document_id);
let folders = this.get('store').peekAll('folder');
let folder = this.get('store').peekRecord('folder', this.get('folderId'));
let document = this.get('store').peekRecord('document', this.get('documentId'));
this.set('document', document);
this.set('folders', folders);
this.set('folder', folder);
return new Ember.RSVP.Promise((resolve) => {
this.get('documentService').getPages(this.get('documentId')).then((pages) => {
this.set('allPages', pages);
this.set('pages', pages.filterBy('pageType', 'section'));
this.set('tabs', pages.filterBy('pageType', 'tab'));
resolve();
});
});
},
model() {
this.browser.setTitle(this.get('document.name'));
this.browser.setMetaDescription(this.get('document.excerpt'));
let document = this.modelFor('document').document;
this.browser.setTitle(document.get('name'));
this.browser.setMetaDescription(document.get('excerpt'));
return Ember.RSVP.hash({
folders: this.get('folders'),
folder: this.get('folder'),
document: this.get('document'),
page: this.get('pageId'),
isEditor: this.get('folderService').get('canEditCurrentFolder'),
allPages: this.get('allPages'),
pages: this.get('pages'),
tabs: this.get('tabs'),
links: this.get('linkService').getDocumentLinks(this.get('documentId'))
folders: this.modelFor('document').folders,
folder: this.modelFor('document').folder,
document: this.modelFor('document').document,
pages: this.get('documentService').getPages(this.modelFor('document').document.get('id')),
links: this.modelFor('document').links,
sections: this.modelFor('document').sections,
isEditor: this.get('folderService').get('canEditCurrentFolder')
});
}
});

View file

@ -1,2 +1,45 @@
{{document/document-view document=model.document links=model.links allPages=model.allPages tabs=model.tabs pages=model.pages folder=model.folder folders=model.folders isEditor=model.isEditor
gotoPage=(action 'gotoPage') onAddBlock=(action 'onAddBlock') onCopyPage=(action 'onCopyPage') onMovePage=(action 'onMovePage') onDeletePage=(action 'onPageDeleted')}}
<div id="wrapper" class={{if toggled 'toggled'}}>
<div id="sidebar-wrapper">
{{document/sidebar-zone folders=model.folders folder=model.folder document=model.document
pages=model.pages sections=model.section links=model.links isEditor=model.isEditor tab=tab
onDocumentDelete=(action 'onDocumentDelete') onSaveTemplate=(action 'onSaveTemplate')
onPageSequenceChange=(action 'onPageSequenceChange') onPageLevelChange=(action 'onPageLevelChange') onGotoPage=(action 'onGotoPage')}}
</div>
<div id="page-content-wrapper">
<div class="{{if toggled 'container' 'container-fluid'}}">
<div class="row">
<div class="col-lg-12">
{{#if toggled}}
<div id="sidebar-toggle" class="pull-right" {{action 'toggleSidebar'}}>
<div class="round-button button-black">
<i class="material-icons">keyboard_arrow_left</i>
</div>
</div>
{{else}}
<div id="sidebar-toggle" class="pull-right" {{action 'toggleSidebar'}}>
<div class="round-button button-black">
<i class="material-icons">keyboard_arrow_right</i>
</div>
</div>
{{/if}}
<div id="zone-document-content" class="zone-document-content">
<div class="back-to-space">
{{#link-to 'folder' model.folder.id model.folder.slug}}
<i class="material-icons">arrow_back</i>&nbsp;{{model.folder.name}}
{{/link-to}}
</div>
{{document/document-heading document=model.document isEditor=model.isEditor onSaveDocument=(action 'onSaveDocument')}}
{{document/document-view document=model.document links=model.links pages=model.pages
folder=model.folder folders=model.folders sections=model.sections isEditor=model.isEditor pageId=pageId
onSavePage=(action 'onSavePage') onInsertSection=(action 'onInsertSection')
onSavePageAsBlock=(action 'onSavePageAsBlock') onDeleteBlock=(action 'onDeleteBlock')
onCopyPage=(action 'onCopyPage') onMovePage=(action 'onMovePage') onDeletePage=(action 'onPageDeleted')}}
</div>
</div>
</div>
</div>
</div>
</div>

View file

@ -16,7 +16,8 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
sectionService: Ember.inject.service('section'),
documentService: Ember.inject.service('document'),
folderService: Ember.inject.service('folder'),
linkService: Ember.inject.service('link'),
beforeModel(transition) {
this.set('pageId', is.not.undefined(transition.queryParams.page) ? transition.queryParams.page : "");
this.set('folderId', this.paramsFor('document').folder_id);
@ -34,13 +35,7 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
this.get('folderService').setCurrentFolder(folder).then(() => {
this.set('isEditor', this.get('folderService').get('canEditCurrentFolder'));
this.get('documentService').getPages(this.get('documentId')).then((pages) => {
this.set('allPages', pages);
this.set('pages', pages.filterBy('pageType', 'section'));
this.set('tabs', pages.filterBy('pageType', 'tab'));
resolve();
});
resolve();
});
});
});
@ -55,14 +50,18 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
document: this.get('document'),
page: this.get('pageId'),
isEditor: this.get('isEditor'),
allPages: this.get('allPages'),
pages: this.get('pages'),
tabs: this.get('tabs'),
sections: this.get('sectionService').getAll().then((sections) => {
return sections.filterBy('pageType', 'section');
}),
links: this.get('linkService').getDocumentLinks(this.get('documentId')),
sections: this.get('sectionService').getAll()
});
},
activate() {
$('body').addClass('background-color-off-white');
},
deactivate() {
$('body').removeClass('background-color-off-white');
},
actions: {
error(error /*, transition*/ ) {

View file

@ -14,12 +14,19 @@ import NotifierMixin from '../../../mixins/notifier';
export default Ember.Controller.extend(NotifierMixin, {
documentService: Ember.inject.service('document'),
queryParams: ['mode'],
mode: null,
actions: {
onCancel() {
this.transitionToRoute('document.index',
this.get('model.folder.id'),
this.get('model.folder.slug'),
this.get('model.document.id'),
this.get('model.document.slug'),
{ queryParams: { pageId: this.get('model.page.id') }});
},
onAction(page, meta) {
this.showNotification("Saving");
this.showNotification("Saved");
let model = {
page: page.toJSON({ includeId: true }),
@ -30,17 +37,14 @@ export default Ember.Controller.extend(NotifierMixin, {
this.audit.record("edited-page");
let data = this.get('store').normalize('page', page);
this.get('store').push(data);
this.get('target.router').refresh();
this.transitionToRoute('document.index',
this.get('model.folder.id'),
this.get('model.folder.slug'),
this.get('model.document.id'),
this.get('model.document.slug'),
{ queryParams: { pageId: page.get('id')}});
});
},
onDelete(document, page) {
this.get('documentService').deletePage(document.get('id'), page.get('id')).then(() => {
this.audit.record("deleted-page");
this.showNotification('Deleted');
this.transitionToRoute('document');
this.get('target.router').refresh();
});
}
}
});

View file

@ -16,28 +16,25 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
documentService: Ember.inject.service('document'),
folderService: Ember.inject.service('folder'),
userService: Ember.inject.service('user'),
pageId: '',
queryParams: {
mode: {
refreshModel: false
}
},
beforeModel(transition) {
this.set('mode', !_.isUndefined(transition.queryParams.mode) ? transition.queryParams.mode : '');
},
model(params) {
return Ember.RSVP.hash({
folders: this.modelFor('document').folders,
folder: this.modelFor('document').folder,
document: this.modelFor('document').document,
pages: this.modelFor('document').pages,
tabs: this.get('documentService').getPages(this.modelFor('document').document.get('id')).then((pages) => {
return pages.filterBy('pageType', 'tab');
}),
isEditor: this.get('folderService').get('canEditCurrentFolder'),
links: this.modelFor('document').links,
sections: this.modelFor('document').sections,
page: this.get('documentService').getPage(this.modelFor('document').document.get('id'), params.page_id),
meta: this.get('documentService').getPageMeta(this.modelFor('document').document.get('id'), params.page_id)
});
},
activate() {
$('body').addClass('background-color-off-white');
},
deactivate() {
$('body').removeClass('background-color-off-white');
}
});

View file

@ -1 +1,17 @@
{{document/document-tab mode=mode model=model onAction=(action 'onAction') onDelete=(action 'onDelete')}}
<div class="zone-section-editor">
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div id="zone-document-content" class="zone-document-content">
<div class="back-to-space">
{{#link-to 'document.index' model.folder.id model.folder.slug model.document.id model.document.slug}}
<i class="material-icons">arrow_back</i>&nbsp;{{model.document.name}}
{{/link-to}}
</div>
{{document/document-heading document=model.document isEditor=false}}
{{document/document-editor document=model.document folder=model.folder page=model.page meta=model.meta onCancel=(action 'onCancel') onAction=(action 'onAction')}}
</div>
</div>
</div>
</div>
</div>

View file

@ -1,13 +1,2 @@
{{layout/zone-navigation}}
{{#layout/zone-sidebar}}
{{document/document-sidebar document=model.document folder=model.folder pages=model.pages page=model.page isEditor=model.isEditor sections=model.sections
onAddSection=(action 'onAddSection') onInsertBlock=(action 'onInsertBlock') onDeleteBlock=(action 'onDeleteBlock') changePageSequence=(action 'onPageSequenceChange') changePageLevel=(action 'onPageLevelChange') gotoPage=(action 'gotoPage')}}
{{/layout/zone-sidebar}}
{{#layout/zone-content}}
{{document/document-toolbar document=model.document pages=model.pages tabs=model.tabs folder=model.folder isEditor=model.isEditor
onSaveTemplate=(action 'onSaveTemplate') onSaveMeta=(action 'onSaveMeta') onDocumentDelete=(action 'onDocumentDelete')}}
{{outlet}}
{{/layout/zone-content}}
{{outlet}}

View file

@ -1,54 +0,0 @@
import Ember from 'ember';
import NotifierMixin from '../../../mixins/notifier';
export default Ember.Controller.extend(NotifierMixin, {
documentService: Ember.inject.service('document'),
actions: {
onCancel() {
this.transitionToRoute('document');
},
onAddSection(section) {
this.audit.record("added-section-" + section.get('contentType'));
let page = {
documentId: this.get('model.document.id'),
title: `${section.get('title')}`,
level: 1,
sequence: 0,
body: "",
contentType: section.get('contentType'),
pageType: section.get('pageType')
};
let meta = {
documentId: this.get('model.document.id'),
rawBody: "",
config: "",
externaleSource: true
};
let model = {
page: page,
meta: meta
};
this.get('documentService').addPage(this.get('model.document.id'), model).then((newPage) => {
let data = this.get('store').normalize('page', newPage);
this.get('store').push(data);
this.get('documentService').getPages(this.get('model.document.id')).then((pages) => {
this.set('model.pages', pages.filterBy('pageType', 'section'));
this.set('model.tabs', pages.filterBy('pageType', 'tab'));
this.get('documentService').getPageMeta(this.get('model.document.id'), newPage.id).then(() => {
let options = {};
options['mode'] = 'edit';
this.transitionToRoute('document.section', newPage.id, { queryParams: options });
});
});
});
}
}
});

View file

@ -1,21 +0,0 @@
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
documentService: Ember.inject.service('document'),
folderService: Ember.inject.service('folder'),
sectionService: Ember.inject.service('section'),
model() {
return Ember.RSVP.hash({
folders: this.modelFor('document').folders,
folder: this.modelFor('document').folder,
document: this.modelFor('document').document,
pages: this.modelFor('document').pages,
tabs: this.modelFor('document').tabs,
sections: this.get('sectionService').getAll().then(function (sections) {
return sections.filterBy('pageType', 'tab');
})
});
}
});

View file

@ -1 +0,0 @@
{{document/page-wizard display='tab' document=model.document folder=model.folder sections=model.sections onCancel=(action 'onCancel') onAddSection=(action 'onAddSection')}}

View file

@ -32,27 +32,15 @@ export default Router.map(function () {
this.route('document', {
path: 's/:folder_id/:folder_slug/d/:document_id/:document_slug'
}, function () {
this.route('files', {
path: 'files'
});
this.route('activity', {
path: 'activity'
});
this.route('section', {
path: 'section/:page_id'
});
this.route('edit', {
path: 'edit/:page_id'
});
this.route('wizard', {
path: 'add'
this.route('block', {
path: 'block/:block_id'
});
this.route('history', {
path: 'history'
});
this.route('block', {
path: 'block/:block_id'
});
});
this.route('customize', {

View file

@ -211,6 +211,9 @@ export default Ember.Service.extend({
getMeta(documentId) {
return this.get('ajax').request(`documents/${documentId}/meta`, {
method: "GET"
}).then((response) => {
return response;
}).catch(() => {
});
},
@ -232,7 +235,6 @@ export default Ember.Service.extend({
// Returns all document pages with content
getPages(documentId) {
return this.get('ajax').request(`documents/${documentId}/pages`, {
method: 'GET'
}).then((response) => {
@ -266,6 +268,7 @@ export default Ember.Service.extend({
}).then((response) => {
let data = this.get('store').normalize('page-meta', response);
return this.get('store').push(data);
}).catch(() => {
});
},

View file

@ -112,21 +112,13 @@ export default Ember.Service.extend({
let documentSlug = is.null(targetDocument) ? "d" : targetDocument.get('slug');
// handle section link
if (link.linkType === "section") {
if (link.linkType === "section" || link.linkType === "tab") {
let options = {};
options['page'] = link.targetId;
options['pageId'] = link.targetId;
router.transitionTo('document', link.folderId, folderSlug, link.documentId, documentSlug, { queryParams: options });
return;
}
// handle tab link
if (link.linkType === "tab") {
let options = {};
options['mode'] = 'view';
router.transitionTo('document.section', link.targetId, { queryParams: options });
return;
}
// handle document link
if (link.linkType === "document") {
router.transitionTo('document', link.folderId, folderSlug, link.documentId, documentSlug);

View file

@ -21,6 +21,7 @@ export default Ember.Service.extend({
appMeta: service(),
store: service(),
pins: [],
initialized: false,
getUserPins() {
let userId = this.get('session.user.id');
@ -41,6 +42,7 @@ export default Ember.Service.extend({
});
this.set('pins', pins);
this.set('initialized', true);
return pins;
});
@ -102,16 +104,32 @@ export default Ember.Service.extend({
isDocumentPinned(documentId) {
let userId = this.get('session.user.id');
let pins = this.get('pins');
let pinId = '';
pins.forEach((pin) => {
if (pin.get('userId') === userId && pin.get('documentId') === documentId) {
pinId = pin.get('id');
}
});
if (this.get('initialized') === false) {
this.getUserPins().then(() => {
let pins = this.get('pins');
let pinId = '';
return pinId;
pins.forEach((pin) => {
if (pin.get('userId') === userId && pin.get('documentId') === documentId) {
pinId = pin.get('id');
}
});
return pinId;
});
} else {
let pins = this.get('pins');
let pinId = '';
pins.forEach((pin) => {
if (pin.get('userId') === userId && pin.get('documentId') === documentId) {
pinId = pin.get('id');
}
});
return pinId;
}
},
isSpacePinned(spaceId) {

View file

@ -67,6 +67,9 @@ export default BaseService.extend({
}
return pages;
}).catch((/*error*/) => {
// we ignore any error to cater for anon users who don't
// have permissions to perform refresh
});
},

411
app/app/snippets.txt Normal file
View file

@ -0,0 +1,411 @@
**********************************
**********************************
***** document
**********************************
**********************************
{{layout/zone-navigation}}
{{#layout/zone-sidebar}}
{{document/document-sidebar document=model.document folder=model.folder pages=model.pages page=model.page isEditor=model.isEditor sections=model.sections
onAddSection=(action 'onAddSection') onInsertBlock=(action 'onInsertBlock') onDeleteBlock=(action 'onDeleteBlock') changePageSequence=(action 'onPageSequenceChange') changePageLevel=(action 'onPageLevelChange') gotoPage=(action 'gotoPage')}}
{{/layout/zone-sidebar}}
{{#layout/zone-content}}
{{document/document-toolbar document=model.document pages=model.pages tabs=model.tabs folder=model.folder isEditor=model.isEditor
onSaveTemplate=(action 'onSaveTemplate') onSaveMeta=(action 'onSaveMeta') onDocumentDelete=(action 'onDocumentDelete')}}
{{outlet}}
{{/layout/zone-content}}
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import NotifierMixin from '../../mixins/notifier';
export default Ember.Controller.extend(NotifierMixin, {
documentService: Ember.inject.service('document'),
templateService: Ember.inject.service('template'),
sectionService: Ember.inject.service('section'),
page: null,
folder: {},
pages: [],
// Jump to the right part of the document.
scrollToPage(pageId) {
Ember.run.schedule('afterRender', function () {
let dest;
let target = "#page-title-" + pageId;
let targetOffset = $(target).offset();
if (is.undefined(targetOffset)) {
return;
}
dest = targetOffset.top > $(document).height() - $(window).height() ? $(document).height() - $(window).height() : targetOffset.top;
// small correction to ensure we also show page title
dest = dest > 50 ? dest - 74 : dest;
$("html,body").animate({
scrollTop: dest
}, 500, "linear");
$(".toc-index-item").removeClass("selected");
$("#index-" + pageId).addClass("selected");
});
},
actions: {
gotoPage(pageId) {
if (is.null(pageId)) {
return;
}
this.scrollToPage(pageId);
},
onPageSequenceChange(changes) {
this.get('documentService').changePageSequence(this.get('model.document.id'), changes).then(() => {
_.each(changes, (change) => {
let pageContent = _.findWhere(this.get('model.pages'), {
id: change.pageId
});
if (is.not.undefined(pageContent)) {
pageContent.set('sequence', change.sequence);
}
});
this.set('model.pages', this.get('model.pages').sortBy('sequence'));
this.get('target.router').refresh();
});
},
onPageLevelChange(changes) {
this.get('documentService').changePageLevel(this.get('model.document.id'), changes).then(() => {
_.each(changes, (change) => {
let pageContent = _.findWhere(this.get('model.pages'), {
id: change.pageId
});
if (is.not.undefined(pageContent)) {
pageContent.set('level', change.level);
}
});
let pages = this.get('model.pages');
pages = pages.sortBy('sequence');
this.set('model.pages', []);
this.set('model.pages', pages);
this.get('target.router').refresh();
});
},
onSaveTemplate(name, desc) {
this.get('templateService').saveAsTemplate(this.get('model.document.id'), name, desc).then(function () {});
},
onSaveMeta(doc) {
this.get('documentService').save(doc).then(() => {
this.transitionToRoute('document.index');
});
},
onAddSection(section) {
this.audit.record("added-section-" + section.get('contentType'));
let page = {
documentId: this.get('model.document.id'),
title: `${section.get('title')}`,
level: 1,
sequence: 0,
body: "",
contentType: section.get('contentType'),
pageType: section.get('pageType')
};
let meta = {
documentId: this.get('model.document.id'),
rawBody: "",
config: ""
};
let model = {
page: page,
meta: meta
};
this.get('documentService').addPage(this.get('model.document.id'), model).then((newPage) => {
let data = this.get('store').normalize('page', newPage);
this.get('store').push(data);
this.get('documentService').getPages(this.get('model.document.id')).then((pages) => {
this.set('model.pages', pages.filterBy('pageType', 'section'));
this.set('model.tabs', pages.filterBy('pageType', 'tab'));
this.get('documentService').getPageMeta(this.get('model.document.id'), newPage.id).then(() => {
this.transitionToRoute('document.edit',
this.get('model.folder.id'),
this.get('model.folder.slug'),
this.get('model.document.id'),
this.get('model.document.slug'),
newPage.id);
});
});
});
},
onInsertBlock(block) {
this.audit.record("added-content-block-" + block.get('contentType'));
let page = {
documentId: this.get('model.document.id'),
title: `${block.get('title')}`,
level: 1,
sequence: 0,
body: block.get('body'),
contentType: block.get('contentType'),
pageType: block.get('pageType'),
blockId: block.get('id')
};
let meta = {
documentId: this.get('model.document.id'),
rawBody: block.get('rawBody'),
config: block.get('config'),
externalSource: block.get('externalSource')
};
let model = {
page: page,
meta: meta
};
this.get('documentService').addPage(this.get('model.document.id'), model).then((newPage) => {
let data = this.get('store').normalize('page', newPage);
this.get('store').push(data);
this.get('documentService').getPages(this.get('model.document.id')).then((pages) => {
this.set('model.pages', pages.filterBy('pageType', 'section'));
this.set('model.tabs', pages.filterBy('pageType', 'tab'));
this.get('documentService').getPageMeta(this.get('model.document.id'), newPage.id).then(() => {
this.transitionToRoute('document.edit',
this.get('model.folder.id'),
this.get('model.folder.slug'),
this.get('model.document.id'),
this.get('model.document.slug'),
newPage.id);
});
});
});
},
onDeleteBlock(blockId) {
this.get('sectionService').deleteBlock(blockId).then(() => {
this.audit.record("deleted-block");
this.send("showNotification", "Deleted");
this.transitionToRoute('document.index');
});
},
onDocumentDelete() {
this.get('documentService').deleteDocument(this.get('model.document.id')).then(() => {
this.audit.record("deleted-page");
this.send("showNotification", "Deleted");
this.transitionToRoute('folder', this.get('model.folder.id'), this.get('model.folder.slug'));
});
}
}
});
**********************************
**********************************
***** document/index
**********************************
**********************************
{{document/document-view document=model.document links=model.links allPages=model.allPages tabs=model.tabs pages=model.pages folder=model.folder folders=model.folders isEditor=model.isEditor gotoPage=(action 'gotoPage') onAddBlock=(action 'onAddBlock') onCopyPage=(action 'onCopyPage') onMovePage=(action 'onMovePage') onDeletePage=(action 'onPageDeleted')}}
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import NotifierMixin from '../../../mixins/notifier';
export default Ember.Controller.extend(NotifierMixin, {
documentService: Ember.inject.service('document'),
sectionService: Ember.inject.service('section'),
queryParams: ['page'],
// Jump to the right part of the document.
scrollToPage(pageId) {
Ember.run.schedule('afterRender', function () {
let dest;
let target = "#page-title-" + pageId;
let targetOffset = $(target).offset();
if (is.undefined(targetOffset)) {
return;
}
dest = targetOffset.top > $(document).height() - $(window).height() ? $(document).height() - $(window).height() : targetOffset.top;
// small correction to ensure we also show page title
dest = dest > 50 ? dest - 74 : dest;
$("html,body").animate({
scrollTop: dest
}, 500, "linear");
$(".toc-index-item").removeClass("selected");
$("#index-" + pageId).addClass("selected");
});
},
actions: {
gotoPage(pageId) {
if (is.null(pageId)) {
return;
}
this.scrollToPage(pageId);
},
onPageSequenceChange(changes) {
this.get('documentService').changePageSequence(this.get('model.document.id'), changes).then(() => {
_.each(changes, (change) => {
let pageContent = _.findWhere(this.get('model.pages'), {
id: change.pageId
});
if (is.not.undefined(pageContent)) {
pageContent.set('sequence', change.sequence);
}
});
this.set('model.pages', this.get('model.pages').sortBy('sequence'));
this.get('target.router').refresh();
});
},
onPageLevelChange(changes) {
this.get('documentService').changePageLevel(this.get('model.document.id'), changes).then(() => {
_.each(changes, (change) => {
let pageContent = _.findWhere(this.get('model.pages'), {
id: change.pageId
});
if (is.not.undefined(pageContent)) {
pageContent.set('level', change.level);
}
});
let pages = this.get('model.pages');
pages = pages.sortBy('sequence');
this.set('model.pages', pages);
this.get('target.router').refresh();
});
},
onAddBlock(block) {
this.get('sectionService').addBlock(block).then(() => {
this.showNotification("Published");
});
},
onCopyPage(pageId, targetDocumentId) {
let documentId = this.get('model.document.id');
this.get('documentService').copyPage(documentId, pageId, targetDocumentId).then(() => {
this.showNotification("Copied");
// refresh data if copied to same document
if (documentId === targetDocumentId) {
this.get('target.router').refresh();
}
});
},
onMovePage(pageId, targetDocumentId) {
let documentId = this.get('model.document.id');
this.get('documentService').copyPage(documentId, pageId, targetDocumentId).then(() => {
this.showNotification("Moved");
this.send('onPageDeleted', { id: pageId, children: false });
});
},
onPageDeleted(deletePage) {
let documentId = this.get('model.document.id');
let pages = this.get('model.pages');
let deleteId = deletePage.id;
let deleteChildren = deletePage.children;
let page = _.findWhere(pages, {
id: deleteId
});
let pageIndex = _.indexOf(pages, page, false);
let pendingChanges = [];
this.audit.record("deleted-page");
// select affected pages
for (var i = pageIndex + 1; i < pages.get('length'); i++) {
if (pages[i].get('level') <= page.get('level')) {
break;
}
pendingChanges.push({
pageId: pages[i].get('id'),
level: pages[i].get('level') - 1
});
}
if (deleteChildren) {
// nuke of page tree
pendingChanges.push({
pageId: deleteId
});
this.get('documentService').deletePages(documentId, deleteId, pendingChanges).then(() => {
// update our models so we don't have to reload from db
for (var i = 0; i < pendingChanges.length; i++) {
let pageId = pendingChanges[i].pageId;
this.set('model.pages', _.reject(pages, function (p) { //jshint ignore: line
return p.get('id') === pageId;
}));
}
this.set('model.pages', _.sortBy(pages, "sequence"));
this.get('target.router').refresh();
});
} else {
// page delete followed by re-leveling child pages
this.get('documentService').deletePage(documentId, deleteId).then(() => {
this.set('model.pages', _.reject(pages, function (p) {
return p.get('id') === deleteId;
}));
this.send('onPageLevelChange', pendingChanges);
});
}
}
}
});

View file

@ -32,3 +32,4 @@
@import "section/table.scss";
@import "section/code.scss";
@import "section/papertrail.scss";
@import "section/wysiwyg.scss";

View file

@ -199,7 +199,7 @@ $i: 150;
$i: 100;
@while $i > 0 {
.width-#{$i} {
width: #{$i}#{"%"};
width: #{$i}#{"%"} !important;
}
$i: $i - 1;
}

View file

@ -41,6 +41,8 @@ $color-symbol-icon: #a4b8be;
$color-table-border: #e1e1e1;
$color-table-header: #f5f5f5;
$color-toolbar: #eeeeee;
$color-wysiwyg: #3c3c3c;
.color-white {
color: $color-white !important;
@ -76,6 +78,9 @@ $color-table-header: #f5f5f5;
.background-color-white {
background-color: $color-white !important;
}
.background-color-off-white {
background-color: $color-off-white !important;
}
.background-color-primary {
background-color: $color-primary !important;
}

View file

@ -1,38 +1,10 @@
.font-fixed-width {
font-family: 'courier new', courier;
}
@font-face {
font-family: 'open_sansbold';
src: url('font/opensans/opensans-bold-webfont.eot');
src: url('font/opensans/opensans-bold-webfont.eot?#iefix') format('embedded-opentype'), url('font/opensans/opensans-bold-webfont.woff2') format('woff2'), url('font/opensans/opensans-bold-webfont.woff') format('woff'), url('font/opensans/opensans-bold-webfont.ttf') format('truetype'), url('font/opensans/opensans-bold-webfont.svg#open_sansbold') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'open_sanslight';
src: url('font/opensans/opensans-light-webfont.eot');
src: url('font/opensans/opensans-light-webfont.eot?#iefix') format('embedded-opentype'), url('font/opensans/opensans-light-webfont.woff2') format('woff2'), url('font/opensans/opensans-light-webfont.woff') format('woff'), url('font/opensans/opensans-light-webfont.ttf') format('truetype'), url('font/opensans/opensans-light-webfont.svg#open_sanslight') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'open_sansregular';
src: url('font/opensans/opensans-regular-webfont.eot');
src: url('font/opensans/opensans-regular-webfont.eot?#iefix') format('embedded-opentype'), url('font/opensans/opensans-regular-webfont.woff2') format('woff2'), url('font/opensans/opensans-regular-webfont.woff') format('woff'), url('font/opensans/opensans-regular-webfont.ttf') format('truetype'), url('font/opensans/opensans-regular-webfont.svg#open_sansregular') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'open_sanssemibold';
src: url('font/opensans/opensans-semibold-webfont.eot');
src: url('font/opensans/opensans-semibold-webfont.eot?#iefix') format('embedded-opentype'), url('font/opensans/opensans-semibold-webfont.woff2') format('woff2'), url('font/opensans/opensans-semibold-webfont.woff') format('woff'), url('font/opensans/opensans-semibold-webfont.ttf') format('truetype'), url('font/opensans/opensans-semibold-webfont.svg#open_sanssemibold') format('svg');
font-weight: normal;
font-style: normal;
}
$font-regular: 'open_sansregular';
$font-semibold: 'open_sanssemibold';
$font-light: 'open_sanslight';
$font-regular: Helvetica;
$font-semibold: Helvetica;
$font-light: Helvetica;
@font-face {
font-family: "Material Icons";

View file

@ -11,31 +11,30 @@
@media print {
.non-printable,
.zone-navigation,
.zone-sidebar {
.zone-sidebar,
#sidebar-wrapper,
.document-heading,
.edit-document-heading,
#sidebar-toggle,
.back-to-space,
.start-section,
.new-section-wizard {
display: none !important;
}
.zone-content {
#page-content-wrapper, #wrapper {
padding: 0 !important;
}
.document-view {
.attachment-zone,
.document-summary,
.document-tags,
.page-toolbar {
display: none !important;
}
.non-printable-message,
.print-title {
display: block !important;
}
}
.doc-layout {
padding: 0 !important;
box-shadow: none !important;
margin: 0 !important;
}
.non-printable-message,
.print-title {
display: block !important;
}
.is-a-tab, .is-a-page {
padding: 0 !important;
margin: 0 !important;
box-shadow: none !important;
}
}

View file

@ -1,38 +1,46 @@
.section-code-editor {
margin-top: 6px;
> .syntax-selector {
margin-bottom: 15px;
}
}
/* BASICS */
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
color: black;
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
color: black;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
padding: 0 4px; /* Horizontal padding of content */
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
background-color: white; /* The little square between H and V scrollbars */
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
white-space: nowrap;
border-right: 1px solid #ddd;
background-color: #f7f7f7;
white-space: nowrap;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
white-space: nowrap;
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
white-space: nowrap;
}
.CodeMirror-guttermarker { color: black; }
@ -41,45 +49,45 @@
/* CURSOR */
.CodeMirror-cursor {
border-left: 1px solid black;
border-right: none;
width: 0;
border-left: 1px solid black;
border-right: none;
width: 0;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
border-left: 1px solid silver;
}
.cm-fat-cursor .CodeMirror-cursor {
width: auto;
border: 0;
background: #7e7;
width: auto;
border: 0;
background: #7e7;
}
.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1;
z-index: 1;
}
.cm-animate-fat-cursor {
width: auto;
border: 0;
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
background-color: #7e7;
width: auto;
border: 0;
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
background-color: #7e7;
}
@-moz-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
0% {}
50% { background-color: transparent; }
100% {}
}
@-webkit-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
0% {}
50% { background-color: transparent; }
100% {}
}
@keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
0% {}
50% { background-color: transparent; }
100% {}
}
/* Can style cursor different in overwrite (non-insert) mode */
@ -88,8 +96,8 @@
.cm-tab { display: inline-block; text-decoration: inherit; }
.CodeMirror-ruler {
border-left: 1px solid #ccc;
position: absolute;
border-left: 1px solid #ccc;
position: absolute;
}
/* DEFAULT THEME */
@ -140,132 +148,132 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
the editor. You probably shouldn't touch them. */
.CodeMirror {
position: relative;
overflow: hidden;
background: white;
position: relative;
overflow: hidden;
background: white;
}
.CodeMirror-scroll {
overflow: scroll !important; /* Things will break if this is overridden */
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
overflow: scroll !important; /* Things will break if this is overridden */
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
}
.CodeMirror-sizer {
position: relative;
border-right: 30px solid transparent;
position: relative;
border-right: 30px solid transparent;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actual scrolling happens, thus preventing shaking and
flickering artifacts. */
before actual scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
z-index: 6;
display: none;
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
right: 0; bottom: 0;
}
.CodeMirror-gutter-filler {
left: 0; bottom: 0;
left: 0; bottom: 0;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
z-index: 3;
position: absolute; left: 0; top: 0;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
display: inline-block;
margin-bottom: -30px;
/* Hack to make IE7 behave */
*zoom:1;
*display:inline;
white-space: normal;
height: 100%;
display: inline-block;
margin-bottom: -30px;
/* Hack to make IE7 behave */
*zoom:1;
*display:inline;
}
.CodeMirror-gutter-wrapper {
position: absolute;
z-index: 4;
background: none !important;
border: none !important;
position: absolute;
z-index: 4;
background: none !important;
border: none !important;
}
.CodeMirror-gutter-background {
position: absolute;
top: 0; bottom: 0;
z-index: 4;
position: absolute;
top: 0; bottom: 0;
z-index: 4;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-gutter-wrapper {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.CodeMirror-lines {
cursor: text;
min-height: 1px; /* prevents collapsing before first draw */
cursor: text;
min-height: 1px; /* prevents collapsing before first draw */
}
.CodeMirror pre {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
-webkit-tap-highlight-color: transparent;
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
-webkit-tap-highlight-color: transparent;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto;
position: relative;
z-index: 2;
overflow: auto;
}
.CodeMirror-widget {}
.CodeMirror-code {
outline: none;
outline: none;
}
/* Force content-box sizing for the elements where we expect it */
@ -274,32 +282,32 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
-moz-box-sizing: content-box;
box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.CodeMirror-measure {
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden;
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-cursor { position: absolute; }
.CodeMirror-measure pre { position: static; }
div.CodeMirror-cursors {
visibility: hidden;
position: relative;
z-index: 3;
visibility: hidden;
position: relative;
z-index: 3;
}
div.CodeMirror-dragcursors {
visibility: visible;
visibility: visible;
}
.CodeMirror-focused div.CodeMirror-cursors {
visibility: visible;
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
@ -309,8 +317,8 @@ div.CodeMirror-dragcursors {
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
.cm-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
background: #ffa;
background: rgba(255, 255, 0, .4);
}
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
@ -320,10 +328,10 @@ div.CodeMirror-dragcursors {
.cm-force-border { padding-right: .1px; }
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursors {
visibility: hidden;
}
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursors {
visibility: hidden;
}
}
/* See issue #2901 */
@ -362,23 +370,23 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png
/* Color scheme for code-mirror */
.cm-s-solarized {
line-height: 1.45em;
color-profile: sRGB;
rendering-intent: auto;
line-height: 1.45em;
color-profile: sRGB;
rendering-intent: auto;
}
.cm-s-solarized.cm-s-dark {
color: #839496;
background-color: #002b36;
text-shadow: #002b36 0 1px;
color: #839496;
background-color: #002b36;
text-shadow: #002b36 0 1px;
}
.cm-s-solarized.cm-s-light {
background-color: #fdf6e3;
color: #657b83;
text-shadow: #eee8d5 0 1px;
background-color: #fdf6e3;
color: #657b83;
text-shadow: #eee8d5 0 1px;
}
.cm-s-solarized .CodeMirror-widget {
text-shadow: none;
text-shadow: none;
}
.cm-s-solarized .cm-header { color: #586e75; }
@ -410,22 +418,22 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png
.cm-s-solarized .cm-tag { color: #93a1a1; }
.cm-s-solarized .cm-attribute { color: #2aa198; }
.cm-s-solarized .cm-hr {
color: transparent;
border-top: 1px solid #586e75;
display: block;
color: transparent;
border-top: 1px solid #586e75;
display: block;
}
.cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; }
.cm-s-solarized .cm-special { color: #6c71c4; }
.cm-s-solarized .cm-em {
color: #999;
text-decoration: underline;
text-decoration-style: dotted;
color: #999;
text-decoration: underline;
text-decoration-style: dotted;
}
.cm-s-solarized .cm-strong { color: #eee; }
.cm-s-solarized .cm-error,
.cm-s-solarized .cm-invalidchar {
color: #586e75;
border-bottom: 1px dotted #dc322f;
color: #586e75;
border-bottom: 1px dotted #dc322f;
}
.cm-s-solarized.cm-s-dark div.CodeMirror-selected { background: #073642; }
@ -440,45 +448,45 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png
/* Little shadow on the view-port of the buffer view */
.cm-s-solarized.CodeMirror {
-moz-box-shadow: inset 7px 0 12px -6px #000;
-webkit-box-shadow: inset 7px 0 12px -6px #000;
box-shadow: inset 7px 0 12px -6px #000;
-moz-box-shadow: inset 7px 0 12px -6px #000;
-webkit-box-shadow: inset 7px 0 12px -6px #000;
box-shadow: inset 7px 0 12px -6px #000;
}
/* Gutter border and some shadow from it */
.cm-s-solarized .CodeMirror-gutters {
border-right: 1px solid;
border-right: 1px solid;
}
/* Gutter colors and line number styling based of color scheme (dark / light) */
/* Dark */
.cm-s-solarized.cm-s-dark .CodeMirror-gutters {
background-color: #002b36;
border-color: #00232c;
background-color: #002b36;
border-color: #00232c;
}
.cm-s-solarized.cm-s-dark .CodeMirror-linenumber {
text-shadow: #021014 0 -1px;
text-shadow: #021014 0 -1px;
}
/* Light */
.cm-s-solarized.cm-s-light .CodeMirror-gutters {
background-color: #fdf6e3;
border-color: #eee8d5;
background-color: #fdf6e3;
border-color: #eee8d5;
}
/* Common */
.cm-s-solarized .CodeMirror-linenumber {
color: #586e75;
padding: 0 5px;
color: #586e75;
padding: 0 5px;
}
.cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; }
.cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; }
.cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; }
.cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text {
color: #586e75;
color: #586e75;
}
.cm-s-solarized .CodeMirror-cursor { border-left: 1px solid #819090; }
@ -488,8 +496,8 @@ Active line. Negative margin compensates left padding of the text in the
view-port
*/
.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background {
background: rgba(255, 255, 255, 0.10);
background: rgba(255, 255, 255, 0.10);
}
.cm-s-solarized.cm-s-light .CodeMirror-activeline-background {
background: rgba(0, 0, 0, 0.10);
background: rgba(0, 0, 0, 0.10);
}

View file

@ -1,13 +1,15 @@
#section-markdown-editor {
.section-markdown-preview {
width: 100%;
resize: none;
padding: 10px;
background-color: white;
margin: 0;
padding: 0;
@extend .no-outline;
margin-top: -10px;
border: none;
@extend .no-outline;
}
#section-markdown-preview {
width: 100%;
padding: 10px;
background-color: white;
overflow: auto;
.section-markdown-preview-button {
position: absolute;
top: 18px;
right: 118px;
}

View file

@ -1,3 +1,7 @@
.table-editor-wrapper {
margin-top: 6px;
}
.fr-element,
.fr-element:focus {
outline: 0px solid transparent;
@ -1165,12 +1169,12 @@ table th.fr-selected-cell {
* Video style
*/
}
.fr-view table {
border: none;
border-collapse: collapse;
empty-cells: show;
max-width: 100%;
}
// .fr-view table {
// border: none;
// border-collapse: collapse;
// empty-cells: show;
// max-width: 100%;
// }
.fr-view table.fr-dashed-borders td,
.fr-view table.fr-dashed-borders th {
border-style: dashed;
@ -1178,25 +1182,25 @@ table th.fr-selected-cell {
.fr-view table.fr-alternate-rows tbody tr:nth-child(2n) {
background: #f5f5f5;
}
.fr-view table td,
.fr-view table th {
border: 1px solid #dddddd;
}
.fr-view table td:empty,
.fr-view table th:empty {
height: 20px;
}
.fr-view table td.fr-highlighted,
.fr-view table th.fr-highlighted {
border: 1px double red;
}
.fr-view table td.fr-thick,
.fr-view table th.fr-thick {
border-width: 2px;
}
.fr-view table th {
background: #e6e6e6;
}
// .fr-view table td,
// .fr-view table th {
// border: 1px solid #dddddd;
// }
// .fr-view table td:empty,
// .fr-view table th:empty {
// height: 20px;
// }
// .fr-view table td.fr-highlighted,
// .fr-view table th.fr-highlighted {
// border: 1px double red;
// }
// .fr-view table td.fr-thick,
// .fr-view table th.fr-thick {
// border-width: 2px;
// }
// .fr-view table th {
// background: #e6e6e6;
// }
.fr-view hr {
clear: both;
user-select: none;

View file

@ -0,0 +1,6 @@
.wysiwyg-editor {
@extend .no-outline;
font-family: Helvetica,Arial,Verdana,sans-serif;
margin-top: -10px;
color: $color-black;
}

File diff suppressed because it is too large Load diff

View file

@ -3,15 +3,13 @@
> .empty-state {
margin: 30px 0;
font-size: 2rem;
font-size: 1.2rem;
color: $color-gray;
font-family: 'open_sanslight';
}
> .normal-state {
margin: 10px;
font-size: 2rem;
font-size: 1.2rem;
color: $color-gray;
font-family: 'open_sanslight';
}
}

View file

@ -1,139 +0,0 @@
.document-activity {
> .metrics {
list-style-type: none;
margin: 0 0 30px;
padding: 0;
width: 100%;
text-align: center;
> .metric {
padding: 0 30px;
display: inline-block;
text-align: center;
.label {
padding: 0 0 10px;
font-family: $font-regular;
font-size: 0.9rem;
color: $color-gray;
}
.number {
font-family: $font-light;
font-size: 2rem;
color: $color-off-black;
}
}
}
> .items {
list-style-type: none;
margin: 0;
padding: 0;
white-space: nowrap;
> .item {
padding: 20px 0;
width: 100%;
border-bottom: 1px solid $color-border;
&:last-of-type {
border-bottom: none !important;
}
> .avatar-box {
display: inline-block;
margin: 3px 10px 0 0;
width: 5%;
}
> .name {
display: inline-block;
font-size: 1rem;
font-family: $font-light;
color: $color-off-black;
width: 25%;
}
> .detail {
display: inline-block;
font-size: 1rem;
font-family: $font-regular;
color: $color-off-black;
width: 45%;
.viewed {
color: $color-goldy;
}
.added {
color: $color-green;
}
.changed {
color: $color-blue;
}
.deleted {
color: $color-red;
}
}
> .date {
display: inline-block;
font-family: $font-light;
font-size: 1rem;
float: right;
width: 15%;
padding-top: 10px;
}
}
}
}
.meta-editors {
position: relative;
> .items {
list-style-type: none;
margin: 0;
padding: 0;
white-space: nowrap;
> .item {
margin: 15px 0;
overflow-x: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 90%;
.avatar-box {
display: inline-block;
margin: 3px 10px 0 0;
vertical-align: top;
}
.detail {
display: inline-block;
.name {
font-size: 1rem;
color: $color-off-black;
}
.changed {
font-size: 0.9rem;
}
.deleted {
font-size: 0.9rem;
color: $color-red;
}
.date {
font-size: 0.8rem;
}
}
}
}
}

View file

@ -1,10 +1,11 @@
@import "activity.scss";
@import "content.scss";
@import "edit-tools.scss";
@import "editor.scss";
@import "files.scss";
@import "content-linker.scss";
@import "history.scss";
@import "sidebar.scss";
@import "toolbar.scss";
@import "wizard.scss";
@import "inline-editor.scss";
@import "layout.scss";
@import "section-editor.scss";
@import "sidebar-view-activity.scss";
@import "sidebar-view-attachments.scss";
@import "sidebar-view-index.scss";
@import "sidebar-zone.scss";
@import "view.scss";
@import "wysiwyg.scss";

View file

@ -1,18 +1,3 @@
.edit-tools {
margin: 0 0 0 20px;
min-height: 600px;
> .toolbar {
margin: 0;
padding: 0;
> .item {
list-style-type: none;
margin: 0 0 20px;
}
}
}
.content-counter-dialog {
width: 200px;
height: 200px;
@ -20,7 +5,7 @@
.content-linker-dialog {
width: 350px;
height: 500px;
height: 350px;
overflow-y: auto;
.link-list {

View file

@ -1,69 +0,0 @@
.wiki-layout {
}
.doc-layout {
padding: 60px 50px;
box-shadow: 0 0 0 0.75pt $color-stroke,0 0 3pt 0.75pt $color-stroke;
margin: 30px 40px 50px 40px;
}
.document-view {
.print-title {
display: none;
font-size: 2.3em;
font-weight: bold;
color:$color-black;
margin-bottom: 20px;
margin-top: 0;
}
.non-printable-message {
display: none;
font-size: 1em;
font-style: italic;
color: $color-gray;
}
.is-template {
color: $color-goldy;
font-weight: bold;
font-size: 1.5em;
margin-bottom: 30px;
padding-bottom: 5px;
border-bottom: 1px dotted $color-goldy;
}
> .pages {
margin: 30px 0 50px 0;
> .wysiwyg {
> .is-a-page {
@extend .transition-all;
&:hover {
.page-title {
> .page-toolbar {
opacity: 1;
}
}
}
.page-title {
> .page-toolbar {
opacity: 0;
}
}
}
}
}
}
.empty-state-document {
margin-top: 150px;
text-align: center;
}
.dropdown-page-toolbar {
width: 300px;
}

View file

@ -1,30 +0,0 @@
.document-editor {
> .toolbar {
width: 100%;
padding: 0;
> .title {
width: 50%;
> .input-control {
margin: 0;
> input {
margin: 0 0 5px;
}
}
}
> .buttons {
margin-top: 10px;
}
}
> .canvas {
padding: 40px 0;
}
.cancel-edits-dialog {
display: none;
}
}

View file

@ -1,72 +1,27 @@
.document-history {
position: relative;
.zone-document-history {
margin-left: 60px;
padding: 20px 60px;
z-index: 777;
position: relative;
> .sidebar {
.diff-zone {
@extend .transition-all;
@include border-radius(2px);
@include ease-in();
position: relative;
overflow-y: scroll;
padding: 25px 50px;
box-shadow: 0 0 0 0.75pt $color-stroke,0 0 3pt 0.75pt $color-stroke;
background-color: $color-white;
> .heading {
font-size: 1.2rem;
font-family: $font-light;
color: $color-off-black;
}
> .line {
width: 2px;
background-color: $color-stroke;
height: 100%;
position: absolute;
left: 17px;
z-index: -1;
}
> .items {
list-style-type: none;
margin: 0;
padding: 20px 0 10px;
white-space: nowrap;
> .item {
margin: 0;
padding: 10px 0;
width: 100%;
color: $color-off-black;
@include ease-in();
cursor: pointer;
> .avatar-box {
display: inline-block;
}
> .date {
display: inline-block;
font-size: 1rem;
font-family: $font-light;
margin-left: 25px;
}
> .detail {
display: block;
font-size: 1.2rem;
font-family: $font-semibold;
margin-left: 65px;
overflow: hidden;
text-overflow: ellipsis;
}
&:hover {
color: $color-link;
}
}
> .deleted {
color: $color-red;
cursor: not-allowed;
&:hover {
color: $color-red;
}
}
> .canvas {
padding: 0;
}
}
.revision-picker {
width: 300px;
float: left;
margin-top: 10px;
display: inline-block;
}
}

View file

@ -0,0 +1,41 @@
.document-editor {
position: relative;
> .toolbar {
width: 100%;
padding: 0;
> .edit-title {
width: 70%;
> input {
font-weight: bold;
font-size: 1.5rem;
margin: 16px 0 10px 0;
color: $color-wysiwyg;
}
}
> .buttons {
margin-top: 17px;
}
}
> .canvas {
padding: 0;
}
.cancel-edits-dialog {
display: none;
}
}
.document-editor-full {
@extend .transition-all;
@include border-radius(2px);
@include ease-in();
position: relative;
padding: 25px 50px;
box-shadow: 0 0 0 0.75pt $color-stroke,0 0 3pt 0.75pt $color-stroke;
background-color: $color-white;
}

View file

@ -0,0 +1,80 @@
$document-sidebar-width: 400px;
#wrapper {
padding-right: 0;
margin-left: 60px;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
background-color: $color-off-white;
}
// #wrapper.toggled {
// padding-right: $document-sidebar-width;
// }
#sidebar-wrapper {
// z-index: 1000;
z-index: 888;
position: fixed;
right: $document-sidebar-width;
width: 0;
height: 100%;
margin-right: -$document-sidebar-width;
overflow-y: auto;
background: $color-off-white;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
border-left: 1px solid $color-stroke;
}
#wrapper.toggled #sidebar-wrapper {
width: $document-sidebar-width;
}
#page-content-wrapper {
width: 100%;
position: absolute;
padding: 30px 70px;
}
#wrapper.toggled #page-content-wrapper {
position: absolute;
margin-left: -$document-sidebar-width;
}
@media(min-width:768px) {
#wrapper {
padding-right: $document-sidebar-width;
}
#wrapper.toggled {
padding-left: 0;
padding-right: 0;
}
#sidebar-wrapper {
width: $document-sidebar-width;
}
#wrapper.toggled #sidebar-wrapper {
width: 0;
.document-sidebar-toolbar {
position: relative;
}
}
#page-content-wrapper {
padding: 20px 60px;
position: relative;
}
#wrapper.toggled #page-content-wrapper {
position: relative;
margin-left: 0;
}
}

View file

@ -0,0 +1,29 @@
.zone-section-editor {
margin-left: 60px;
padding: 20px 60px;
z-index: 777;
position: relative;
.section-editor {
@extend .transition-all;
@include border-radius(2px);
@include ease-in();
position: relative;
padding: 25px 50px;
box-shadow: 0 0 0 0.75pt $color-stroke,0 0 3pt 0.75pt $color-stroke;
background-color: $color-white;
> .buttons {
margin-top: 17px;
float: right;
}
> .canvas {
padding: 0;
}
.cancel-edits-dialog {
display: none;
}
}
}

View file

@ -1,9 +0,0 @@
.document-section {
> .toolbar {
margin-bottom: 10px;
> .buttons {
margin: 10px 0;
}
}
}

View file

@ -0,0 +1,52 @@
.document-sidebar-view-activity {
> .items {
list-style-type: none;
margin: 0;
padding: 0;
white-space: nowrap;
> .item {
margin: 0;
padding: 10px 0;
width: 100%;
> .avatar-box {
display: inline-block;
margin: 0 10px 0 0;
}
> .name {
display: inline-block;
font-size: 0.9rem;
color: $color-gray;
width: 200px;
@extend .truncate;
}
> .detail {
display: block;
font-size: 0.9rem;
color: $color-off-black;
margin-left: 50px;
width: 200px;
@extend .truncate;
.viewed {
color: $color-goldy;
}
.added {
color: $color-green;
}
.changed {
color: $color-blue;
}
.deleted {
color: $color-red;
}
}
}
}
}

View file

@ -1,17 +1,16 @@
.document-files {
.document-sidebar-view-attachments {
margin: 0;
> .upload-document-files {
width: 50%;
width: 100%;
padding: 20px;
margin: 0 auto;
margin-bottom: 20px;
text-align: center;
color: $color-gray;
border: 2px dotted $color-gray;
border: 1px solid $color-stroke;
cursor: pointer;
font-size: 1rem;
font-size: 0.9rem;
line-height: 1.7rem;
@include border-radius(10px);
@include ease-in();
&:hover {
@ -31,11 +30,10 @@
> .item {
color: $color-off-black;
margin-top: 10px;
padding: 0;
margin: 0;
padding: 10px 0;
font-size: 0.9rem;
list-style-type: none;
border-bottom: 1px solid $color-border;
padding-bottom: 10px;
&:last-of-type {
border-bottom: none !important;
@ -46,6 +44,8 @@
}
> a {
@extend .truncate;
width: 200px;
color: $color-gray;
&:hover {
@ -53,7 +53,10 @@
}
> .file {
font-size: 1rem;
@extend .truncate;
display: inline-block;
font-size: 0.9rem;
width: 200px;
}
}

View file

@ -0,0 +1,57 @@
.document-sidebar-view-index {
margin: 0;
>.structure {
> .toc-controls {
margin: 0;
color: $color-gray;
> .round-button-mono {
> .material-icons {
color: $color-link;
}
}
> .disabled {
@extend .cursor-not-allowed;
color: $color-stroke;
border-color: $color-stroke;
> .material-icons {
color: $color-stroke;
}
}
}
> .index-list {
padding: 0;
list-style: none;
font-size: 13px;
overflow-x: hidden;
list-style-type: none;
margin: 20px 0 0;
.item {
padding: 4px 0;
text-overflow: ellipsis;
word-wrap: break-word;
white-space: nowrap;
overflow: hidden;
@extend .no-select;
> .link {
color: $color-off-black;
&:hover {
color: $color-link;
}
}
> .selected {
color: $color-link;
font-weight: bold;
}
}
}
}
}

View file

@ -0,0 +1,66 @@
.document-sidebar-common {
display: inline-block;
width: 340px;
padding: 40px 20px 40px 20px;
> .pinner {
cursor: pointer;
> .material-icons {
color: $color-primary;
}
}
> .template-header {
color: $color-goldy;
font-size: 1.5em;
margin-bottom: 20px;
}
}
.document-sidebar-toolbar {
display: inline-block;
width: 60px;
background-color: $color-toolbar;
text-align: center;
position: fixed;
right: 0;
top: 0;
height: 100%;
padding: 50px 0 0 0;
> .selected {
background-color: $color-off-black !important;
border: none;
> .material-icons {
color: $color-white !important;
}
}
> .round-button-mono {
> .material-icons {
color: $color-gray;
}
}
}
.document-sidebar-wrapper {
padding: 40px 20px 40px 20px;
margin-right: 60px;
.document-sidebar-panel {
width: 300px;
// top: 0;
// bottom: 0;
// position: fixed;
// overflow-y: scroll;
// overflow-x: hidden;
> .title {
color: $color-primary;
font-size: 1.1rem;
margin-bottom: 30px;
}
}
}

View file

@ -1,115 +0,0 @@
.document-sidebar {
@extend .no-select;
width: 100%;
.stuck-toc {
position: fixed;
top: 20px;
-webkit-animation: fadein 1s;
-moz-animation: fadein 1s;
-ms-animation: fadein 1s;
-o-animation: fadein 1s;
animation: fadein 1s;
}
.section-tool {
position: absolute;
top: 130px;
right: -18px;
z-index: 999;
}
.scroll-tool {
position: absolute;
top: 130px;
right: -18px;
z-index: 999;
-webkit-animation: fadein 1s;
-moz-animation: fadein 1s;
-ms-animation: fadein 1s;
-o-animation: fadein 1s;
animation: fadein 1s;
}
.stuck-tool {
position: fixed !important;
top: 130px !important;
right: 0;
left: 0;
-webkit-animation: fadein 1s;
-moz-animation: fadein 1s;
-ms-animation: fadein 1s;
-o-animation: fadein 1s;
animation: fadein 1s;
}
.close-action {
float: right;
> .round-button-mono {
color: $color-stroke;
border-color: $color-stroke;
> .material-icons {
color: $color-stroke;
}
}
}
.document-structure {
> .toc-controls {
margin: 0;
color: $color-gray;
> .round-button-mono {
color: $color-green;
border-color: $color-green;
> .material-icons {
color: $color-green;
}
}
> .disabled {
@extend .cursor-not-allowed;
color: $color-stroke;
border-color: $color-stroke;
> .material-icons {
color: $color-stroke;
}
}
}
.entries {
padding: 0;
list-style: none;
font-size: 13px;
overflow-x: hidden;
list-style-type: none;
margin: 20px 0 0;
font-family: $font-semibold;
.item {
padding: 4px 0;
text-overflow: ellipsis;
word-wrap: break-word;
white-space: nowrap;
overflow: hidden;
> .link {
color: $color-gray;
&:hover {
color: $color-link;
}
}
> .selected {
color: $color-link;
font-weight: bold;
}
}
}
}
}

View file

@ -1,114 +0,0 @@
.document-toolbar {
position: relative;
margin: -30px 0 40px;
height: 60px;
padding: 5px 30px 0;
background-color: $color-sidebar;
@include border-radius-bottom-right(5px);
@include border-radius-bottom-left(5px);
@extend .no-select;
> .tabs {
width: 70%;
height: 50px;
margin-top: 15px;
display: inline-block;
> .tab {
list-style-type: none;
display: inline-block;
margin: 0 20px 0 0;
padding: 0;
color: $color-gray;
font-family: $font-semibold;
cursor: pointer;
&:hover {
color: $color-link;
}
> a {
color: $color-gray;
@include ease-in();
&:hover {
color: $color-link;
}
}
> .active {
color: $color-link;
> .add-tab {
> i {
color: $color-link;
}
}
}
.add-tab {
display: inline-block;
vertical-align: text-top;
@include ease-in();
> i {
font-size: 1.5rem;
color: $color-gray;
&:hover {
color: $color-link;
}
}
}
}
}
> .options {
width: 30%;
height: 50px;
margin-top: 15px;
display: inline-block;
text-align: right;
float: right;
> .option {
list-style-type: none;
display: inline-block;
margin: 0 0 0 20px;
padding: 0;
color: $color-gray;
cursor: pointer;
@include ease-in();
&:hover {
color: $color-link;
}
> .pinned {
color: $color-primary;
}
}
> a {
display: inline-block;
> .option {
list-style-type: none;
display: inline-block;
margin: 0 0 0 20px;
padding: 0;
color: $color-gray;
cursor: pointer;
@include ease-in();
&:hover {
color: $color-link;
}
> .pinned {
color: $color-primary;
}
}
}
}
}

View file

@ -0,0 +1,349 @@
.zone-document {
min-height: 500px; //ensure dropdowns render in viewport
height: 100%;
margin-left: 60px;
padding: 30px 70px;
z-index: 777;
}
.zone-document-content {
> .back-to-space {
margin: 10px 0;
> a {
vertical-align: middle;
color: $color-primary;
font-size: 1rem;
> .material-icons {
font-size: 1rem;
vertical-align: middle;
}
}
}
.doc-title {
font-size: 2rem;
margin: 30px 0 10px;
font-weight: normal;
}
.doc-excerpt {
font-size: 1rem;
color: $color-gray;
margin: 0 0 45px;
}
.edit-document-heading {
margin: 30px 0 0 0;
.edit-doc-title {
> input {
font-size: 2rem;
font-weight: normal;
margin: 0 0 10px;
color: $color-wysiwyg;
}
}
.edit-doc-excerpt {
font-size: 1rem;
margin: 0 0 10px;
color: $color-gray;
}
}
}
.document-view {
margin: 0 0 50px 0;
.is-a-page {
@extend .transition-all;
@include border-radius(2px);
@include ease-in();
padding: 25px 50px;
box-shadow: 0 0 0 0.75pt $color-stroke,0 0 3pt 0.75pt $color-stroke;
background-color: $color-white;
&:hover {
.page-title {
> .page-toolbar {
opacity: 1;
}
}
}
.page-title {
> .page-toolbar {
opacity: 0;
}
}
}
.is-a-tab {
@include border-radius(2px);
@include ease-in();
padding: 25px 50px;
box-shadow: 0 0 0 0.75pt $color-stroke,0 0 3pt 0.75pt $color-stroke;
background-color: $color-white;
.icon {
text-align: center;
display: inline-block;
width: 40px;
vertical-align: bottom;
margin-right: 5px;
> .img {
text-align: center;
display: inline-block;
height: 30px;
width: 30px;
}
}
> .title {
font-size: 1.3rem;
font-weight: normal;
color: $color-off-black;
letter-spacing: 0.5px;
margin-top: 8px;
}
&:hover {
.page-title {
> .page-toolbar {
opacity: 1;
}
}
}
.page-title {
> .page-toolbar {
opacity: 0;
}
}
}
.tab-min {
padding: 0px 50px;
height: 65px;
overflow: hidden;
cursor: default;
.page-title {
> .page-toolbar {
opacity: 1;
}
}
}
.tab-max {
padding: 25px 50px;
height: auto;
overflow: auto;
cursor: normal;
}
.section-divider {
height: 60px;
background-color: transparent;
}
.start-section {
@extend .no-select;
height: 60px;
background-color: transparent;
position: relative;
cursor: pointer;
> .start-button {
display: none;
text-align: center;
padding-top: 20px;
color: $color-green;
font-size: 1rem;
position: relative;
> .round-button {
opacity: 0.6 !important;
}
> .label {
display: inline-block;
margin-left: 10px;
}
> .line {
display: inline-block;
height: 1px;
border: 1px solid $color-green;
width: 100px;
margin: 0 20px 0 20px;
opacity: 0.2;
}
}
&:first-of-type {
height: 30px;
> .start-button {
padding-top: 0;
}
}
}
.start-section-empty-state {
> .start-button {
display: block;
}
}
.new-section-wizard {
@include border-radius(2px);
margin: 0 0 30px 0;
padding: 30px;
border: 1px solid $color-stroke;
background-color: $color-off-white;
display: none;
.section-name {
font-weight: bold;
font-size: 1.5rem;
margin: 0 0 30px 0;
color: $color-black;
}
.template-caption {
color: $color-gray;
margin: 10px 0 10px 0;
font-size: 1.2rem;
}
> .list-wrapper {
height: 440px;
overflow-y: auto;
> .preset-list {
margin: 0;
padding: 0;
> .item {
@include ease-in();
@include border-radius(4px);
list-style: none;
cursor: pointer;
display: inline-block;
border: 1px solid $color-stroke;
background-color: $color-white;
margin: 0 20px 20px 0;
padding: 15px 0 0 20px;
width: 200px;
height: 60px;
&:hover {
@include ease-in();
border-color: $color-link;
}
.icon {
text-align: center;
display: inline-block;
width: 40px;
margin-right: 10px;
float: left;
> .img {
text-align: center;
display: inline-block;
height: 30px;
width: 30px;
float: left;
}
}
> .title {
font-size: 1rem;
font-weight: normal;
color: $color-off-black;
letter-spacing: 0.5px;
margin-top: 6px;
}
}
}
> .block-list {
margin: 0;
padding: 0;
> .item {
@include ease-in();
@include border-radius(4px);
list-style: none;
cursor: pointer;
display: inline-block;
border: 1px solid $color-stroke;
background-color: $color-white;
margin: 0 20px 20px 0;
padding: 12px 0 0 20px;
width: 423px;
height: 60px;
position: relative;
&:hover {
@include ease-in();
border-color: $color-link;
> .block-actions {
display: block;
}
}
> .block-actions {
@include ease-in();
display: none;
position: absolute;
top: 10px;
right: 8px;
.material-icons {
color: $color-stroke;
font-size: 1rem;
}
}
> .details {
width: 350px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
> .title {
font-size: 1rem;
font-weight: normal;
color: $color-off-black;
letter-spacing: 0.5px;
margin-top: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
> .desc {
color: $color-gray;
font-size: 0.8rem;
margin-top: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
}
}
}
.dropdown-page-toolbar {
width: 300px;
}

View file

@ -1,172 +0,0 @@
.section-wizard {
margin: 20px 0 30px;
> .canvas {
padding: 0;
> .divider {
margin: 30px 0 20px 0;
border-top: 1px dotted $color-gray;
}
> .template-caption {
text-align: center;
color: $color-gray;
padding-bottom: 10px;
}
> .list {
margin: 0;
padding: 0;
> .min-height {
min-height: 87px;
}
> .item {
list-style: none;
cursor: pointer;
padding: 10px 0;
margin: 5px 0;
@include ease-in();
&:hover {
@include ease-in();
>.icon {
.actions {
display: inline-block;
}
}
> .details {
> .title {
color: $color-link;
}
> .desc {
color: $color-link;
}
}
}
.icon {
text-align: center;
display: inline-block;
width: 50px;
> .img {
text-align: center;
display: inline-block;
height: 40px;
width: 40px;
}
> .actions {
display: none;
vertical-align: top;
text-align: center;
margin-top: 5px;
opacity: 0.5;
> .material-icons, a {
color: $color-gray;
&:hover {
color: $color-link;
}
}
}
}
> .details {
vertical-align: top;
display: inline-block;
width: 80%;
> .title {
font-size: 1rem;
font-weight: bold;
color: $color-off-black;
letter-spacing: 0.5px;
}
> .desc {
color: $color-gray;
font-size: 0.9rem;
margin-top: 5px;
}
}
}
}
}
}
.tab-wizard {
margin: 20px 0 30px;
> .canvas {
padding: 0;
> .list {
margin: 0;
padding: 0;
> .item {
list-style: none;
cursor: pointer;
padding: 20px;
@include ease-in();
&:hover {
@include ease-in();
> .details {
> .title {
color: $color-primary;
}
> .desc {
color: $color-primary;
}
}
}
.icon {
text-align: center;
display: inline-block;
width: 50px;
margin-right: 10px;
float: left;
> .img {
float: left;
text-align: center;
display: inline-block;
height: 40px;
width: 40px;
}
}
> .details {
vertical-align: top;
display: inline-block;
float: left;
> .title {
font-size: 1rem;
font-weight: bold;
color: $color-off-black;
letter-spacing: 0.5px;
}
> .desc {
color: $color-gray;
font-size: 0.9rem;
margin-top: 5px;
}
}
}
}
}
}

View file

@ -1,115 +1,100 @@
.wysiwyg {
// font-size: 1rem;
font-size: 15px;
line-height: 30px;
color: #3c3c3c;
table
{
// width: auto !important;
font-size: 17px;
line-height: 30px;
color: $color-wysiwyg;
table {
@include border(1px);
td
{
td {
padding: 5px 7px !important;
@include border(1px);
p
{
p {
margin: 0 !important;
padding: 0 !important;
}
}
}
ol, ul
{
ol,
ul {
margin: 15px 0;
padding: 0 0 0 40px;
line-height: 20px;
}
ul
{
li
{
list-style-type: disc;
ol {
li {
list-style-type: decimal;
line-height: 20px;
}
}
b
{
font-family: $font-semibold;
ul {
li {
list-style-type: disc;
line-height: 20px;
}
}
h1 {
font-size: 2em;
font-family: $font-semibold;
font-size: 1.7rem;
font-weight: bold;
margin: 16px 0;
}
// h1
// {
// font-size: 1.6em;
// font-family: open_sanslight;
// color:$color-off-black;
// margin: 0 0 20px 0;
// }
h2
{
font-size: 1.7em;
margin: 30px 0 20px 0;
font-family: $font-regular;
}
h3
{
h2 {
font-size: 1.5rem;
margin: 30px 0 20px 0;
font-family: $font-regular;
font-weight: bold;
margin: 16px 0;
}
h4
{
h3 {
font-size: 1.3rem;
margin: 30px 0 20px 0;
font-family: $font-regular;
font-weight: bold;
margin: 16px 0;
}
h5, h6, h7, h8, h9
{
font-size: 1.3rem;
margin: 30px 0 20px 0;
font-family: $font-regular;
h4,
h5,
h6,
h7,
h8,
h9 {
font-size: 1.1rem;
font-weight: bold;
margin: 16px 0;
}
h2, h3, h4, h5, h6, h7, h8, h9
{
.page-title
{
color:$color-off-black;
font-family: $font-regular;
h2,
h3,
h4,
h5,
h6,
h7,
h8,
h9 {
.page-title {
color: $color-off-black;
}
}
pre
{
pre {
background-color: $color-off-white;
padding: 10px;
border: 1px solid $color-border;
@include border-radius(3px);
}
.code-mirror
{
.code-mirror {
background-color: none;
padding: 10px;
border: none;
@include border-radius(0px);
}
.wysiwyg-table
{
.wysiwyg-table {
border: none;
border-collapse: collapse;
empty-cells: show;
@ -118,30 +103,36 @@
.fr-dashed-borders td,
.fr-dashed-borders th {
border-style: dashed;
border-style: dashed;
}
.fr-alternate-rows tbody tr:nth-child(2n) {
background: #f5f5f5;
background: #f5f5f5;
}
td,
th {
border: 1px solid #f3f5f8;
padding: 5px 7px !important;
border: 1px solid #f3f5f8;
padding: 5px 7px !important;
}
td:empty,
th:empty {
height: 20px;
height: 20px;
}
td.fr-highlighted,
th.fr-highlighted {
border: 1px double red;
border: 1px double red;
}
td.fr-thick,
th.fr-thick {
border-width: 2px;
border-width: 2px;
}
th {
background: #f7f6f6;
background: #f7f6f6;
}
}
}

View file

@ -1,13 +1,14 @@
.zone-navigation {
position: fixed;
margin: 0;
padding: 0;
top: 0;
width: 60px;
min-height: 100%;
height: 100%;
background-color: $color-primary;
margin: 0;
padding: 0;
z-index: 999;
overflow-x: hidden;
background-color: $color-primary;
> .bottom-zone,
> .top-zone {
@ -80,7 +81,6 @@
font-size: 1rem;
font-style: normal;
line-height: 2.6rem;
font-family: open_sansregular;
}
}
@ -111,7 +111,7 @@
> .pin {
cursor: pointer;
margin: 20px 0 20px 9px;
padding: 11px 3px;
padding: 14px 3px;
height: 40px;
width: 40px;
text-align: center;

View file

@ -3,7 +3,7 @@
background-color: $color-gray;
@include border-radius(20px);
@include ease-in();
padding: 7px 0 0 0;
padding: 10px 0 0 0;
letter-spacing: 1px;
text-align: center;
height: 35px;

View file

@ -138,6 +138,13 @@
}
}
.round-button-small {
width: 20px;
height: 20px;
line-height: 20px;
font-size: 0.9rem;
}
.square-button {
display: inline-block;
position: relative;
@ -217,6 +224,13 @@
@include button-hover-state($color-white);
}
.button-black {
border: none;
background-color: $color-off-black;
color: $color-white;
@include button-hover-state($color-black);
}
.button-transparent {
background-color: transparent;
color: $color-gray;

View file

@ -5,7 +5,7 @@
padding: 0;
height: 25px;
line-height: 0;
margin-right: 5px;
margin: 0 5px 10px 0;
background-color: $color-chip;
color: $color-chip-text;

View file

@ -81,7 +81,7 @@
&:hover {
color: $color-link;
font-weight: bold;
// font-weight: bold;
}
a, a:visited {
@ -92,7 +92,7 @@
&:hover {
color: $color-link;
font-weight: bold;
// font-weight: bold;
}
}
}
@ -106,7 +106,7 @@
&:hover {
color: $color-red;
font-weight: bold;
// font-weight: bold;
}
}

View file

@ -15,8 +15,8 @@
}
> .tip {
color: $color-input;
font-size: 1em;
color: $color-gray;
font-size: 0.9em;
margin: 5px 0 10px;
padding: 0;
text-align: left;
@ -161,6 +161,18 @@
box-shadow: none !important;
}
}
.error-inline {
border-left: 3px solid $color-red;
}
}
.input-transparent {
background-color: transparent !important;
> input, textarea {
background-color: transparent !important;
}
}
.form-bordered {

View file

@ -1 +1 @@
{{component editorType document=document folder=folder page=page meta=meta onCancel=(action 'onCancel') onAction=(action 'onAction')}}
{{component editorType document=document folder=folder page=page meta=meta blockMode=true onCancel=(action 'onCancel') onAction=(action 'onAction')}}

View file

@ -0,0 +1,72 @@
{{#dropdown-dialog target=contentLinkerButtonId position="bottom right" button="Insert" color="flat-blue" onAction=(action 'onInsertLink')}}
<div class="content-linker-dialog">
<form>
{{ui/ui-tab tabs=tabs onTabSelect=(action 'onTabSelect')}}
<div class="margin-top-40" />
{{#if showSections}}
<ul class="link-list">
{{#each candidates.pages as |p|}}
<li class="link-item" {{ action 'setSelection' p }}>
{{#ui/ui-selection selected=p.selected}}
{{p.title}}
{{/ui/ui-selection}}
</li>
{{/each}}
</ul>
{{/if}}
{{#if showAttachments}}
<ul class="link-list">
{{#each candidates.attachments as |a|}}
<li class="link-item" {{ action 'setSelection' a }}>
{{#ui/ui-selection selected=a.selected}}
<img class="icon" src="/assets/img/attachments/{{document/file-icon a.context}}" />
{{ a.title }}
{{/ui/ui-selection}}
</li>
{{/each}}
</ul>
{{/if}}
{{#if showSearch}}
<div class="input-control">
<label>Search</label>
<div class="tip">For content or attachments</div>
{{focus-input id="content-linker-search" type="input" value=keywords placeholder="keyword search" autocomplete="off"}}
</div>
{{#unless hasMatches}}
Nothing found.
{{/unless}}
<ul class="link-list">
{{#each matches.documents as |m|}}
<li class="link-item" {{ action 'setSelection' m }}>
{{#ui/ui-selection selected=m.selected}}
{{m.title}}
{{/ui/ui-selection}}
</li>
{{/each}}
{{#each matches.pages as |m|}}
<li class="link-item" {{ action 'setSelection' m }}>
{{#ui/ui-selection selected=m.selected}}
{{m.title}}<br/><span class="color-gray">{{m.context}}</span>
{{/ui/ui-selection}}
</li>
{{/each}}
{{#each matches.attachments as |a|}}
<li class="link-item" {{ action 'setSelection' a }}>
{{#ui/ui-selection selected=a.selected}}
<img class="icon" src="/assets/img/attachments/{{document/file-icon a.context}}" />
{{ a.title }}
{{/ui/ui-selection}}
</li>
{{/each}}
</ul>
{{/if}}
<div class="hide regular-button button-blue pull-right" {{ action 'onInsertLink' }}>Insert</div>
<div class="hide clearfix" />
</form>
</div>
{{/dropdown-dialog}}

Some files were not shown because too many files have changed in this diff Show more