1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-08-09 15:35:27 +02:00

Merge branch 'master' into github-extension

This commit is contained in:
Elliott Stoneham 2016-06-26 22:25:31 +01:00
commit 8efb288f75
14 changed files with 639 additions and 307 deletions

18
.tern-project Normal file
View file

@ -0,0 +1,18 @@
{
"libs": [
"browser",
"jquery",
"underscore",
"is",
"ember"
],
"loadEagerly": [
"app/app/*.js"
],
"plugins": {
"requirejs": {
"baseURL": "./",
"paths": {}
}
}
}

View file

@ -12,6 +12,7 @@
import Ember from 'ember'; import Ember from 'ember';
import NotifierMixin from '../../mixins/notifier'; import NotifierMixin from '../../mixins/notifier';
import TooltipMixin from '../../mixins/tooltip'; import TooltipMixin from '../../mixins/tooltip';
import tocUtil from '../../utils/toc';
export default Ember.Component.extend(NotifierMixin, TooltipMixin, { export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
document: {}, document: {},
@ -77,332 +78,99 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
// Controls what user can do with the toc (left sidebar). // Controls what user can do with the toc (left sidebar).
// Identifies the target pages. // Identifies the target pages.
setState(pageId) { setState(pageId) {
// defaults this.set('page', pageId);
this.set('tocTools.UpTarget', "");
this.set('tocTools.DownTarget', ""); let toc = this.get('pages');
this.set('tocTools.AllowIndent', false); let page = _.findWhere(toc, { id: pageId });
this.set('tocTools.AllowOutdent', false);
this.set('actionablePage', false); let state = tocUtil.getState(toc, page);
this.set('upDisabled', true);
this.set('downDisabled', true);
this.set('indentDisabled', true);
this.set('outdentDisabled', true);
if (!this.get('isEditor') || is.empty(pageId)) { if (!this.get('isEditor') || is.empty(pageId)) {
return; state.actionablePage = state.upDisabled = state.downDisabled = state.indentDisabled = state.outdentDisabled = false;
} }
this.set('page', pageId); this.set('state', state);
var toc = this.get('pages');
var page = _.findWhere(toc, {
id: pageId
});
// handle root node
if (is.undefined(page) || page.level === 1) {
return;
}
var index = _.indexOf(toc, page, false);
if (index === -1) {
return;
}
var upPage = toc[index - 1];
var downPage = toc[index + 1];
if (_.isUndefined(upPage)) {
this.set('tocTools.UpTarget', "");
}
if (_.isUndefined(downPage)) {
this.set('tocTools.DownTarget', "");
}
// can we go up?
// can we indent?
if (!_.isUndefined(upPage)) {
// can only go up if someone is same or higher level?
var index2 = _.indexOf(toc, upPage, false);
if (index2 !== -1) {
// up
for (var i = index2; i > 0; i--) {
if (page.level > toc[i].level) {
break;
}
if (page.level === toc[i].level) {
this.set('tocTools.UpTarget', toc[i].id);
break;
}
}
// indent?
for (var i2 = index2; i2 > 0; i2--) {
if (toc[i2].level < page.level) {
this.set('tocTools.AllowIndent', false);
break;
}
if (page.level === toc[i2].level) {
this.set('tocTools.AllowIndent', true);
break;
}
}
}
// if page above is root node then some things you can't do
if (upPage.level === 1) {
this.set('tocTools.AllowIndent', false);
this.set('tocTools.UpTarget', "");
}
}
// can we go down?
if (!_.isUndefined(downPage)) {
// can only go down if someone below is at our level or higher
var index3 = _.indexOf(toc, downPage, false);
if (index3 !== -1) {
for (var i3 = index3; i3 < toc.length; i3++) {
if (toc[i3].level < page.level) {
break;
}
if (page.level === toc[i3].level) {
this.set('tocTools.DownTarget', toc[i3].id);
break;
}
}
}
if (page.level > downPage.level) {
this.set('tocTools.DownTarget', "");
}
}
// can we outdent?
this.set('tocTools.AllowOutdent', page.level > 2);
this.set('upDisabled', this.get('tocTools.UpTarget') === "");
this.set('downDisabled', this.get('tocTools.DownTarget') === "");
this.set('indentDisabled', !this.get('tocTools.AllowIndent'));
this.set('outdentDisabled', !this.get('tocTools.AllowOutdent'));
this.set('actionablePage',
is.not.empty(this.get('tocTools.UpTarget')) ||
is.not.empty(this.get('tocTools.DownTarget')) ||
this.get('tocTools.AllowIndent') ||
this.get('tocTools.AllowOutdent'));
}, },
actions: { actions: {
// Page up - above pages shunt down. // Page up - above pages shunt down.
pageUp() { pageUp() {
if (this.upDisabled) { if (this.get('state.upDisabled')) {
return; return;
} }
var pages = this.get('pages'); let state = this.get('state');
var current = _.findWhere(pages, { let pages = this.get('pages');
id: this.get('page') let page = _.findWhere(pages, { id: this.get('page') });
}); let pendingChanges = tocUtil.moveUp(state, pages, page);
var page1 = _.findWhere(pages, {
id: this.tocTools.UpTarget
});
var page2 = null;
var pendingChanges = [];
if (is.undefined(current) || is.undefined(page1)) { if (pendingChanges.length > 0) {
return; this.attrs.changePageSequence(pendingChanges);
}
var index1 = _.indexOf(pages, page1, false); this.send('onEntryClick', this.get('page'));
this.audit.record("moved-page-up");
if (index1 !== -1 && index1 > 1) { this.showNotification("Moved up");
page2 = pages[index1 - 1]; }
}
var sequence1 = page1.sequence;
var sequence2 = is.not.null(page2) ? page2.sequence : 1024;
var index = _.indexOf(pages, current, false);
if (index !== -1) {
var sequence = (sequence1 + sequence2) / 2;
pendingChanges.push({
pageId: current.id,
sequence: sequence
});
for (var i = index + 1; i < pages.length; i++) {
if (pages[i].level <= current.level) {
break;
}
sequence = (sequence + page1.sequence) / 2;
pendingChanges.push({
pageId: pages[i].id,
sequence: sequence
});
}
}
this.attrs.changePageSequence(pendingChanges);
this.send('onEntryClick', this.get('page'));
this.audit.record("moved-page-up");
this.showNotification("Moved up");
}, },
// Move down -- pages below shift up. // Move down -- pages below shift up.
pageDown() { pageDown() {
if (this.downDisabled) { if (this.get('state.downDisabled')) {
return; return;
} }
let state = this.get('state');
var pages = this.get('pages'); var pages = this.get('pages');
var current = _.findWhere(pages, { var page = _.findWhere(pages, { id: this.get('page') });
id: this.get('page') let pendingChanges = tocUtil.moveDown(state, pages, page);
});
var pageIndex = _.indexOf(pages, current, false);
var downTarget = _.findWhere(pages, {
id: this.tocTools.DownTarget
});
var downTargetIndex = _.indexOf(pages, downTarget, false);
var pendingChanges = [];
if (pageIndex === -1 || downTargetIndex === -1) { if (pendingChanges.length > 0) {
return; this.attrs.changePageSequence(pendingChanges);
}
var startingSequence = 0; this.send('onEntryClick', this.get('page'));
var upperSequence = 0; this.audit.record("moved-page-down");
var cutOff = _.rest(pages, downTargetIndex); this.showNotification("Moved down");
var siblings = _.reject(cutOff, function(p) { }
return p.level !== current.level || p.id === current.id || p.id === downTarget.id;
});
if (siblings.length > 0) {
var aboveThisGuy = siblings[0];
var belowThisGuy = pages[_.indexOf(pages, aboveThisGuy, false) - 1];
if (is.not.null(belowThisGuy) && belowThisGuy.level > current.level) {
startingSequence = (aboveThisGuy.sequence + belowThisGuy.sequence) / 2;
upperSequence = aboveThisGuy.sequence;
} else {
var otherGuy = pages[downTargetIndex + 1];
startingSequence = (otherGuy.sequence + downTarget.sequence) / 2;
upperSequence = otherGuy.sequence;
}
} else {
startingSequence = downTarget.sequence * 2;
upperSequence = startingSequence * 2;
}
pendingChanges.push({
pageId: current.id,
sequence: startingSequence
});
var sequence = (startingSequence + upperSequence) / 2;
for (var i = pageIndex + 1; i < pages.length; i++) {
if (pages[i].level <= current.level) {
break;
}
var sequence2 = (sequence + upperSequence) / 2;
pendingChanges.push({
pageId: pages[i].id,
sequence: sequence2
});
}
this.attrs.changePageSequence(pendingChanges);
this.send('onEntryClick', this.get('page'));
this.audit.record("moved-page-down");
this.showNotification("Moved down");
}, },
// Indent - changes a page from H2 to H3, etc. // Indent - changes a page from H2 to H3, etc.
pageIndent() { pageIndent() {
if (this.indentDisabled) { if (this.get('state.indentDisabled')) {
return; return;
} }
let state = this.get('state');
var pages = this.get('pages'); var pages = this.get('pages');
var current = _.findWhere(pages, { var page = _.findWhere(pages, { id: this.get('page') });
id: this.get('page') let pendingChanges = tocUtil.indent(state, pages, page);
});
var pageIndex = _.indexOf(pages, current, false);
var pendingChanges = [];
pendingChanges.push({ if (pendingChanges.length > 0) {
pageId: current.id, this.attrs.changePageLevel(pendingChanges);
level: current.level + 1
});
for (var i = pageIndex + 1; i < pages.length; i++) { this.showNotification("Indent");
if (pages[i].level <= current.level) { this.audit.record("changed-page-sequence");
break; this.send('onEntryClick', this.get('page'));
} }
pendingChanges.push({
pageId: pages[i].id,
level: pages[i].level + 1
});
}
this.attrs.changePageLevel(pendingChanges);
this.showNotification("Indent");
this.audit.record("changed-page-sequence");
this.send('onEntryClick', this.get('page'));
}, },
// Outdent - changes a page from H3 to H2, etc. // Outdent - changes a page from H3 to H2, etc.
pageOutdent() { pageOutdent() {
if (this.outdentDisabled) { if (this.get('state.outdentDisabled')) {
return; return;
} }
let state = this.get('state');
var pages = this.get('pages'); var pages = this.get('pages');
var current = _.findWhere(pages, { var page = _.findWhere(pages, { id: this.get('page') });
id: this.get('page') let pendingChanges = tocUtil.outdent(state, pages, page);
});
var pageIndex = _.indexOf(pages, current, false);
var pendingChanges = [];
pendingChanges.push({ if (pendingChanges.length > 0) {
pageId: current.id, this.attrs.changePageLevel(pendingChanges);
level: current.level - 1
});
for (var i = pageIndex + 1; i < pages.length; i++) { this.showNotification("Outdent");
if (pages[i].level <= current.level) { this.audit.record("changed-page-sequence");
break; this.send('onEntryClick', this.get('page'));
} }
pendingChanges.push({
pageId: pages[i].id,
level: pages[i].level - 1
});
}
this.attrs.changePageLevel(pendingChanges);
this.showNotification("Outdent");
this.audit.record("changed-page-sequence");
this.send('onEntryClick', this.get('page'));
}, },
onEntryClick(id) { onEntryClick(id) {

View file

@ -16,14 +16,14 @@ export default Ember.Component.extend({
tagName: "li", tagName: "li",
classNames: ["item"], classNames: ["item"],
indentLevel: Ember.computed('page', function() { // indentLevel: Ember.computed('page', function() {
let nodeLevel = this.get('page.level'); // let nodeLevel = this.get('page.level');
let indent = (nodeLevel - 1) * 20; // let indent = (nodeLevel - 1) * 20;
return indent; // return indent;
}), // }),
didReceiveAttrs() { didReceiveAttrs() {
this.set('classNames', ["item", "margin-left-" + this.get("indentLevel")]); // this.set('classNames', ["item", "margin-left-" + this.get("page.tocIndent")]);
}, },
actions: { actions: {
@ -31,4 +31,4 @@ export default Ember.Component.extend({
this.get('onClick')(id); this.get('onClick')(id);
} }
} }
}); });

View file

@ -19,7 +19,7 @@ export default Ember.Controller.extend(NotifierMixin, {
let page = models.PageModel.create({ let page = models.PageModel.create({
documentId: this.get('model.document.id'), documentId: this.get('model.document.id'),
title: `${section.title} Section`, title: `${section.title} Section`,
level: 2, level: 1,
sequence: 2048, sequence: 2048,
body: "", body: "",
contentType: section.contentType contentType: section.contentType

View file

@ -16,9 +16,9 @@ $color-primary: #084d85;
$color-link: #5abc67; $color-link: #5abc67;
$color-attachment: #2180cc; $color-attachment: #2180cc;
$color-red: #d9493c; $color-red: #d9493c;
$color-green: #5abc67; $color-green: #1c962b;
$color-blue: #084d85; $color-blue: #084d85;
$color-gray: #99a2ac; $color-gray: #8b9096;
$color-background: #f8f8f8; $color-background: #f8f8f8;
$color-tooltip: #4c4c4c; $color-tooltip: #4c4c4c;
$color-toast: #4c4c4c; $color-toast: #4c4c4c;

View file

@ -1,6 +1,6 @@
.avatar { .avatar {
color: $color-white; color: $color-white;
background-color: $color-stroke; background-color: $color-gray;
@include border-radius(20px); @include border-radius(20px);
padding: 8px 0 0 0; padding: 8px 0 0 0;
letter-spacing: 1px; letter-spacing: 1px;
@ -11,7 +11,7 @@
.avatar-large { .avatar-large {
color: $color-white; color: $color-white;
background-color: $color-stroke; background-color: $color-gray;
@include border-radius(100px); @include border-radius(100px);
height: 100px; height: 100px;
width: 100px; width: 100px;

View file

@ -1,19 +1,19 @@
<div class="document-structure hidden-xs hidden-sm"> <div class="document-structure hidden-xs hidden-sm">
{{#if this.session.authenticated}} {{#if this.session.authenticated}}
<div id="tocToolbar" class="toc-controls {{if actionablePage 'current-page' ''}}"> <div id="tocToolbar" class="toc-controls {{if state.actionablePage 'current-page' ''}}">
<div id="toc-up-button" class="round-button-mono {{if upDisabled 'disabled'}}" data-tooltip="Move up" data-tooltip-position="top center" {{action 'pageUp'}}> <div id="toc-up-button" class="round-button-mono {{if state.upDisabled 'disabled'}}" data-tooltip="Move up" data-tooltip-position="top center" {{action 'pageUp'}}>
<i class="material-icons">arrow_upward</i> <i class="material-icons">arrow_upward</i>
</div> </div>
<div class="button-gap" /> <div class="button-gap" />
<div id="toc-down-button" class="round-button-mono {{if downDisabled 'disabled'}}" data-tooltip="Move down" data-tooltip-position="top center" {{action 'pageDown'}}> <div id="toc-down-button" class="round-button-mono {{if state.downDisabled 'disabled'}}" data-tooltip="Move down" data-tooltip-position="top center" {{action 'pageDown'}}>
<i class="material-icons">arrow_downward</i> <i class="material-icons">arrow_downward</i>
</div> </div>
<div class="button-gap" /> <div class="button-gap" />
<div id="toc-outdent-button" class="round-button-mono {{if outdentDisabled 'disabled'}}" data-tooltip="Outdent" data-tooltip-position="top center" {{action 'pageOutdent'}}> <div id="toc-outdent-button" class="round-button-mono {{if state.outdentDisabled 'disabled'}}" data-tooltip="Outdent" data-tooltip-position="top center" {{action 'pageOutdent'}}>
<i class="material-icons">format_indent_decrease</i> <i class="material-icons">format_indent_decrease</i>
</div> </div>
<div class="button-gap" /> <div class="button-gap" />
<div id="toc-indent-button" class="round-button-mono {{if indentDisabled 'disabled'}}" data-tooltip="Indent" data-tooltip-position="top center" {{action 'pageIndent'}}> <div id="toc-indent-button" class="round-button-mono {{if state.indentDisabled 'disabled'}}" data-tooltip="Indent" data-tooltip-position="top center" {{action 'pageIndent'}}>
<i class="material-icons">format_indent_increase</i> <i class="material-icons">format_indent_increase</i>
</div> </div>
</div> </div>

View file

@ -36,7 +36,7 @@
{{#each pages key="id" as |page index|}} {{#each pages key="id" as |page index|}}
<div class="wysiwyg"> <div class="wysiwyg">
<div id="page-{{ page.id }}" class="is-a-page" data-id="{{ page.id }}" data-type="{{ page.contentType }}"> <div id="page-{{ page.id }}" class="is-a-page" data-id="{{ page.id }}" data-type="{{ page.contentType }}">
{{document/page-heading tagName=page.tagName document=document folder=folder page=page isEditor=isEditor onDeletePage=(action 'onDeletePage') }} {{document/page-heading tagName=page.tagName document=document folder=folder page=page isEditor=isEditor onDeletePage=(action 'onDeletePage')}}
{{section/base-renderer page=page}} {{section/base-renderer page=page}}
</div> </div>
</div> </div>

View file

@ -1 +1 @@
<a id="index-{{page.id}}" class="link toc-index-item" {{action 'onClick' page.id}}>{{page.title}}</a> <a id="index-{{page.id}}" class="link toc-index-item {{page.tocIndentCss}}" {{action 'onClick' page.id}}>{{page.title}}</a>

View file

@ -1,4 +1,4 @@
{{#dropdown-dialog target="start-document-button" position="bottom right" button="Add" color="flat-green" onAction=(action 'startDocument') button2=canEditTemplate color2="flat-blue" onAction2=(action 'editTemplate') onOpenCallback=(action 'onOpenCallback')}} {{#dropdown-dialog target="start-document-button" position="bottom right" button="Start" color="flat-green" onAction=(action 'startDocument') button2=canEditTemplate color2="flat-blue" onAction2=(action 'editTemplate') onOpenCallback=(action 'onOpenCallback')}}
<div class="upload-container"> <div class="upload-container">
<div id="upload-documents" class="regular-button button-green">Import Word / Markdown</div> <div id="upload-documents" class="regular-button button-green">Import Word / Markdown</div>
</div> </div>

View file

@ -1,11 +1,11 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved. // Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
// //
// This software (Documize Community Edition) is licensed under // This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
// //
// You can operate outside the AGPL restrictions by purchasing // You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license // Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>. // by contacting <sales@documize.com>.
// //
// https://documize.com // https://documize.com
@ -198,7 +198,16 @@ let PageModel = BaseModel.extend({
tagName: Ember.computed('level', function() { tagName: Ember.computed('level', function() {
return "h" + this.get('level'); return "h" + this.get('level');
}) }),
tocIndent: Ember.computed('level', function() {
return (this.get('level') - 1) * 20;
}),
tocIndentCss: Ember.computed('tocIndent', function() {
let tocIndent = this.get('tocIndent');
return `margin-left-${tocIndent}`;
}),
}); });
let PageMetaModel = BaseModel.extend({ let PageMetaModel = BaseModel.extend({
@ -235,4 +244,4 @@ export default {
ProtectedFolderParticipant, ProtectedFolderParticipant,
UserModel, UserModel,
SectionModel SectionModel
}; };

286
app/app/utils/toc.js Normal file
View file

@ -0,0 +1,286 @@
// 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
function getState(toc, page) {
let state = {
tocTools: {
upTarget: "",
downTarget: "",
indentIncrement: 0,
allowIndent: false,
allowOutdent: false
},
actionablePage: false,
upDisabled: true,
downDisabled: true,
indentDisabled: true,
outdentDisabled: true,
};
if (is.undefined(page)) {
return state;
}
var index = _.indexOf(toc, page, false);
if (index === -1) {
return state;
}
var upPage = toc[index - 1];
var downPage = toc[index + 1];
if (_.isUndefined(upPage)) {
state.tocTools.upTarget = '';
}
if (_.isUndefined(downPage)) {
state.tocTools.downTarget = '';
}
// can we go up?
// can we indent?
if (!_.isUndefined(upPage)) {
// can only go up if someone is same or higher level?
var index2 = _.indexOf(toc, upPage, false);
if (index2 !== -1) {
// up
for (var i = index2; i >= 0; i--) {
if (page.level > toc[i].level) {
break;
}
if (page.level === toc[i].level) {
state.tocTools.upTarget = toc[i].id;
break;
}
}
// indent?
state.tocTools.allowIndent = upPage.level >= page.level;
state.tocTools.indentIncrement = upPage.level - page.level;
if (state.tocTools.indentIncrement === 0) {
state.tocTools.indentIncrement = 1;
}
// for (var i2 = index2; i2 >= 0; i2--) {
// if (page.level < toc[i2].level) {
// state.tocTools.allowIndent = false;
// break;
// }
//
// if (page.level === toc[i2].level) {
// state.tocTools.allowIndent = true;
// break;
// }
// }
}
}
// can we go down?
if (!_.isUndefined(downPage)) {
// can only go down if someone below is at our level or higher
var index3 = _.indexOf(toc, downPage, false);
if (index3 !== -1) {
for (var i3 = index3; i3 < toc.length; i3++) {
if (toc[i3].level < page.level) {
break;
}
if (page.level === toc[i3].level) {
state.tocTools.downTarget = toc[i3].id;
break;
}
}
}
if (page.level > downPage.level) {
state.tocTools.downTarget = '';
}
}
// can we outdent?
state.tocTools.allowOutdent = page.level > 1;
state.upDisabled = state.tocTools.upTarget === '';
state.downDisabled = state.tocTools.downTarget === '';
state.indentDisabled = !state.tocTools.allowIndent;
state.outdentDisabled = !state.tocTools.allowOutdent;
state.actionablePage = is.not.empty(state.tocTools.upTarget) ||
is.not.empty(state.tocTools.downTarget) ||
state.tocTools.allowIndent || state.tocTools.allowOutdent;
return state;
}
// move up page and any associated kids
function moveUp(state, pages, current) {
var page1 = _.findWhere(pages, { id: state.tocTools.upTarget });
var page2 = null;
var pendingChanges = [];
if (is.undefined(current) || is.undefined(page1)) {
return pendingChanges;
}
var index1 = _.indexOf(pages, page1, false);
if (index1 !== -1) {
page2 = pages[index1 - 1];
}
var sequence1 = page1.sequence;
var sequence2 = is.not.null(page2) && is.not.undefined(page2) ? page2.sequence : 0;
var index = _.indexOf(pages, current, false);
if (index !== -1) {
var sequence = (sequence1 + sequence2) / 2;
pendingChanges.push({
pageId: current.id,
sequence: sequence
});
for (var i = index + 1; i < pages.length; i++) {
if (pages[i].level <= current.level) {
break;
}
sequence = (sequence + page1.sequence) / 2;
pendingChanges.push({
pageId: pages[i].id,
sequence: sequence
});
}
}
return pendingChanges;
}
// move down page and any associated kids
function moveDown(state, pages, current) {
var pageIndex = _.indexOf(pages, current, false);
var downTarget = _.findWhere(pages, { id: state.tocTools.downTarget });
var downTargetIndex = _.indexOf(pages, downTarget, false);
var pendingChanges = [];
if (pageIndex === -1 || downTargetIndex === -1) {
return pendingChanges;
}
var startingSequence = 0;
var upperSequence = 0;
var cutOff = _.rest(pages, downTargetIndex);
var siblings = _.reject(cutOff, function(p) {
return p.level !== current.level || p.id === current.id || p.id === downTarget.id;
});
if (siblings.length > 0) {
var aboveThisGuy = siblings[0];
var belowThisGuy = pages[_.indexOf(pages, aboveThisGuy, false) - 1];
if (is.not.null(belowThisGuy) && belowThisGuy.level > current.level) {
startingSequence = (aboveThisGuy.sequence + belowThisGuy.sequence) / 2;
upperSequence = aboveThisGuy.sequence;
} else {
var otherGuy = pages[downTargetIndex + 1];
startingSequence = (otherGuy.sequence + downTarget.sequence) / 2;
upperSequence = otherGuy.sequence;
}
} else {
// startingSequence = downTarget.sequence * 2;
startingSequence = cutOff[cutOff.length-1].sequence * 2;
upperSequence = startingSequence * 2;
}
pendingChanges.push({
pageId: current.id,
sequence: startingSequence
});
var sequence = (startingSequence + upperSequence) / 2;
for (var i = pageIndex + 1; i < pages.length; i++) {
if (pages[i].level <= current.level) {
break;
}
var sequence2 = (sequence + upperSequence) / 2;
pendingChanges.push({
pageId: pages[i].id,
sequence: sequence2
});
}
return pendingChanges;
}
// indent page and any associated kisds
function indent(state, pages, current) {
var pageIndex = _.indexOf(pages, current, false);
var pendingChanges = [];
pendingChanges.push({
pageId: current.id,
level: current.level + state.tocTools.indentIncrement
});
for (var i = pageIndex + 1; i < pages.length; i++) {
if (pages[i].level <= current.level) {
break;
}
pendingChanges.push({
pageId: pages[i].id,
level: pages[i].level + state.tocTools.indentIncrement
});
}
return pendingChanges;
}
function outdent(state, pages, current) {
var pageIndex = _.indexOf(pages, current, false);
var pendingChanges = [];
pendingChanges.push({
pageId: current.id,
level: current.level - 1
});
for (var i = pageIndex + 1; i < pages.length; i++) {
if (pages[i].level <= current.level) {
break;
}
pendingChanges.push({
pageId: pages[i].id,
level: pages[i].level - 1
});
}
return pendingChanges;
}
export default {
getState,
moveUp,
moveDown,
indent,
outdent
};

View file

@ -0,0 +1,251 @@
import toc from 'documize/utils/toc';
import models from 'documize/utils/model';
import { module, test } from 'qunit';
module('Unit | Utility | toc');
test('toc can only move down', function(assert) {
let pages = [];
pages.pushObject(models.PageModel.create({ id: "1", level: 1, sequence: 1024 })); //testing
pages.pushObject(models.PageModel.create({ id: "2", level: 1, sequence: 1024*2 }));
let state = toc.getState(pages, pages[0]);
assert.equal(state.tocTools.upTarget, '', 'Has no up target');
assert.equal(state.tocTools.downTarget, '2', 'Has down target');
assert.equal(state.tocTools.allowIndent, false, 'Cannot indent');
assert.equal(state.tocTools.allowOutdent, false, 'Cannot outdent');
});
test('toc can move up or indent', function(assert) {
let pages = [];
pages.pushObject(models.PageModel.create({ id: "1", level: 1, sequence: 1024 }));
pages.pushObject(models.PageModel.create({ id: "2", level: 1, sequence: 1024*2 })); //testing
let state = toc.getState(pages, pages[1]);
assert.equal(state.tocTools.upTarget, '1', 'Has up target');
assert.equal(state.tocTools.downTarget, '', 'Has no down target');
assert.equal(state.tocTools.allowIndent, true, 'Can indent');
assert.equal(state.tocTools.allowOutdent, false, 'Cannot outdent');
});
test('toc can only outdent', function(assert) {
let pages = [];
pages.pushObject(models.PageModel.create({ id: "1", level: 1, sequence: 1024 }));
pages.pushObject(models.PageModel.create({ id: "2", level: 1, sequence: 1024*2 }));
pages.pushObject(models.PageModel.create({ id: "3", level: 2, sequence: 1024*3 })); // testing
pages.pushObject(models.PageModel.create({ id: "4", level: 1, sequence: 1024*4 }));
let state = toc.getState(pages, pages[2]);
assert.equal(state.tocTools.upTarget, '', 'Has no up target');
assert.equal(state.tocTools.downTarget, '', 'Has no down target');
assert.equal(state.tocTools.allowIndent, false, 'Cannot indent');
assert.equal(state.tocTools.allowOutdent, true, 'Can outdent');
});
test('toc child can move up or indent', function(assert) {
let pages = [];
pages.pushObject(models.PageModel.create({ id: "1", level: 1, sequence: 1024 }));
pages.pushObject(models.PageModel.create({ id: "2", level: 1, sequence: 1024*2 }));
pages.pushObject(models.PageModel.create({ id: "3", level: 2, sequence: 1024*3 })); // testing
pages.pushObject(models.PageModel.create({ id: "4", level: 1, sequence: 1024*4 }));
let page = pages[3];
let state = toc.getState(pages, page);
assert.equal(state.tocTools.upTarget, '2', 'Has up target');
assert.equal(state.tocTools.downTarget, '', 'Has no down target');
assert.equal(state.tocTools.allowIndent, true, 'Can indent');
assert.equal(state.tocTools.allowOutdent, false, 'Cannot outdent');
let pendingChanges = toc.indent(state, pages, page);
assert.equal(pendingChanges.length, 1, 'Has 1 pending change');
assert.equal(pendingChanges[0].pageId, 4);
assert.equal(pendingChanges[0].level, 2);
});
test('toc top node can indent two places', function(assert) {
let pages = [];
pages.pushObject(models.PageModel.create({ id: "1", level: 1, sequence: 1024 }));
pages.pushObject(models.PageModel.create({ id: "2", level: 1, sequence: 1024*2 }));
pages.pushObject(models.PageModel.create({ id: "3", level: 2, sequence: 1024*3 }));
pages.pushObject(models.PageModel.create({ id: "4", level: 3, sequence: 1024*4 }));
pages.pushObject(models.PageModel.create({ id: "5", level: 1, sequence: 1024*5 })); // testing
let page = pages[4];
let state = toc.getState(pages, page);
assert.equal(state.tocTools.upTarget, '2', 'Has up target');
assert.equal(state.tocTools.downTarget, '', 'Has no down target');
assert.equal(state.tocTools.allowIndent, true, 'Can indent');
assert.equal(state.tocTools.allowOutdent, false, 'Cannot outdent');
let pendingChanges = toc.indent(state, pages, page);
assert.equal(pendingChanges.length, 1, 'Has 1 pending change');
assert.equal(pendingChanges[0].pageId, 5);
assert.equal(pendingChanges[0].level, 3);
});
test('toc top node with kids can indent two places', function(assert) {
let pages = [];
pages.pushObject(models.PageModel.create({ id: "1", level: 1, sequence: 1024 }));
pages.pushObject(models.PageModel.create({ id: "2", level: 1, sequence: 1024*2 }));
pages.pushObject(models.PageModel.create({ id: "3", level: 2, sequence: 1024*3 }));
pages.pushObject(models.PageModel.create({ id: "4", level: 3, sequence: 1024*4 }));
pages.pushObject(models.PageModel.create({ id: "5", level: 1, sequence: 1024*5 })); // testing
pages.pushObject(models.PageModel.create({ id: "6", level: 2, sequence: 1024*6 })); // testing
pages.pushObject(models.PageModel.create({ id: "7", level: 3, sequence: 1024*7 })); // testing
let page = pages[4];
let state = toc.getState(pages, page);
assert.equal(state.tocTools.upTarget, '2', 'Has up target');
assert.equal(state.tocTools.downTarget, '', 'Has no down target');
assert.equal(state.tocTools.allowIndent, true, 'Can indent');
assert.equal(state.tocTools.allowOutdent, false, 'Cannot outdent');
let pendingChanges = toc.indent(state, pages, page);
assert.equal(pendingChanges.length, 3, 'Has 1 pending change');
assert.equal(pendingChanges[0].pageId, 5);
assert.equal(pendingChanges[0].level, 3);
assert.equal(pendingChanges[1].pageId, 6);
assert.equal(pendingChanges[1].level, 4);
assert.equal(pendingChanges[2].pageId, 7);
assert.equal(pendingChanges[2].level, 5);
});
test('toc same level node with kids can indent one place', function(assert) {
let pages = [];
pages.pushObject(models.PageModel.create({ id: "1", level: 1, sequence: 1024 }));
pages.pushObject(models.PageModel.create({ id: "2", level: 1, sequence: 1024*2 }));
pages.pushObject(models.PageModel.create({ id: "3", level: 2, sequence: 1024*3 }));
pages.pushObject(models.PageModel.create({ id: "4", level: 2, sequence: 1024*4 })); // testing
pages.pushObject(models.PageModel.create({ id: "5", level: 3, sequence: 1024*5 }));
pages.pushObject(models.PageModel.create({ id: "6", level: 1, sequence: 1024*6 }));
pages.pushObject(models.PageModel.create({ id: "7", level: 2, sequence: 1024*7 }));
let page = pages[3];
let state = toc.getState(pages, page);
assert.equal(state.tocTools.upTarget, '3', 'Has up target');
assert.equal(state.tocTools.downTarget, '', 'Has no down target');
assert.equal(state.tocTools.allowIndent, true, 'Can indent');
assert.equal(state.tocTools.allowOutdent, true, 'Can outdent');
let pendingChanges = toc.indent(state, pages, page);
assert.equal(pendingChanges.length, 2, 'Has 2 pending changes');
assert.equal(pendingChanges[0].pageId, 4);
assert.equal(pendingChanges[0].level, 3);
assert.equal(pendingChanges[1].pageId, 5);
assert.equal(pendingChanges[1].level, 4);
});
test('toc child with deep tree moves correctly', function(assert) {
let pages = [];
pages.pushObject(models.PageModel.create({ id: "1", level: 1, sequence: 1024 }));
pages.pushObject(models.PageModel.create({ id: "2", level: 1, sequence: 1024*2 }));
pages.pushObject(models.PageModel.create({ id: "3", level: 2, sequence: 1024*4 })); // testing
pages.pushObject(models.PageModel.create({ id: "4", level: 3, sequence: 1024*5 })); // testing
pages.pushObject(models.PageModel.create({ id: "5", level: 3, sequence: 1024*6 })); // testing
pages.pushObject(models.PageModel.create({ id: "6", level: 3, sequence: 1024*7 })); // testing
pages.pushObject(models.PageModel.create({ id: "7", level: 1, sequence: 1024*8 }));
pages.pushObject(models.PageModel.create({ id: "8", level: 1, sequence: 1024*9 }));
pages.pushObject(models.PageModel.create({ id: "9", level: 1, sequence: 1024*10 }));
let page = pages[2];
let state = toc.getState(pages, page);
assert.equal(state.tocTools.upTarget, '', 'Has no up target');
assert.equal(state.tocTools.downTarget, '', 'Has no down target');
assert.equal(state.tocTools.allowIndent, false, 'Cannot indent');
assert.equal(state.tocTools.allowOutdent, true, 'Can outdent');
let pendingChanges = toc.outdent(state, pages, page);
assert.equal(pendingChanges.length, 4, 'Have 4 pending changes');
assert.equal(pendingChanges[0].pageId, 3);
assert.equal(pendingChanges[0].level, 1);
assert.equal(pendingChanges[1].pageId, 4);
assert.equal(pendingChanges[1].level, 2);
assert.equal(pendingChanges[2].pageId, 5);
assert.equal(pendingChanges[2].level, 2);
assert.equal(pendingChanges[3].pageId, 6);
assert.equal(pendingChanges[3].level, 2);
});
test('toc top level node skips down some', function(assert) {
let pages = [];
pages.pushObject(models.PageModel.create({ id: "1", level: 1, sequence: 110 })); // testing
pages.pushObject(models.PageModel.create({ id: "2", level: 1, sequence: 220 }));
pages.pushObject(models.PageModel.create({ id: "3", level: 2, sequence: 330 }));
pages.pushObject(models.PageModel.create({ id: "4", level: 3, sequence: 440 }));
pages.pushObject(models.PageModel.create({ id: "5", level: 3, sequence: 550 }));
pages.pushObject(models.PageModel.create({ id: "6", level: 3, sequence: 660 }));
pages.pushObject(models.PageModel.create({ id: "7", level: 1, sequence: 770 }));
pages.pushObject(models.PageModel.create({ id: "8", level: 1, sequence: 880 }));
pages.pushObject(models.PageModel.create({ id: "9", level: 1, sequence: 990 }));
let page = pages[0];
let state = toc.getState(pages, page);
assert.equal(state.tocTools.upTarget, '', 'Has no up target');
assert.equal(state.tocTools.downTarget, '2', 'Has down target');
assert.equal(state.tocTools.allowIndent, false, 'Cannot indent');
assert.equal(state.tocTools.allowOutdent, false, 'Cannot outdent');
let pendingChanges = toc.moveDown(state, pages, page);
assert.equal(pendingChanges.length, 1, 'Have 1 pending change');
assert.equal(pendingChanges[0].pageId, 1);
assert.equal(pendingChanges[0].sequence, (660+770)/2);
});
test('toc top level node skips up some', function(assert) {
let pages = [];
pages.pushObject(models.PageModel.create({ id: "1", level: 1, sequence: 110 }));
pages.pushObject(models.PageModel.create({ id: "2", level: 1, sequence: 220 }));
pages.pushObject(models.PageModel.create({ id: "3", level: 2, sequence: 330 }));
pages.pushObject(models.PageModel.create({ id: "4", level: 3, sequence: 440 }));
pages.pushObject(models.PageModel.create({ id: "5", level: 3, sequence: 550 }));
pages.pushObject(models.PageModel.create({ id: "6", level: 3, sequence: 660 }));
pages.pushObject(models.PageModel.create({ id: "7", level: 1, sequence: 770 })); // testing
pages.pushObject(models.PageModel.create({ id: "8", level: 1, sequence: 880 }));
pages.pushObject(models.PageModel.create({ id: "9", level: 1, sequence: 990 }));
let page = pages[6];
let state = toc.getState(pages, page);
assert.equal(state.tocTools.upTarget, '2', 'Has up target');
assert.equal(state.tocTools.downTarget, '8', 'Has down target');
assert.equal(state.tocTools.allowIndent, true, 'Can indent');
assert.equal(state.tocTools.allowOutdent, false, 'Cannot outdent');
let pendingChanges = toc.moveUp(state, pages, page);
assert.equal(pendingChanges.length, 1, 'Has 1 pending change');
assert.equal(pendingChanges[0].pageId, 7);
assert.equal(pendingChanges[0].sequence, (110+220)/2);
});
test('toc move down top node to bottom', function(assert) {
let pages = [];
pages.pushObject(models.PageModel.create({ id: "1", level: 1, sequence: 110 }));
pages.pushObject(models.PageModel.create({ id: "2", level: 1, sequence: 220 }));
pages.pushObject(models.PageModel.create({ id: "3", level: 2, sequence: 330 }));
let page = pages[0];
let state = toc.getState(pages, page);
assert.equal(state.tocTools.upTarget, '', 'Has no up target');
assert.equal(state.tocTools.downTarget, '2', 'Has down target');
assert.equal(state.tocTools.allowIndent, false, 'Cannot indent');
assert.equal(state.tocTools.allowOutdent, false, 'Cannot outdent');
let pendingChanges = toc.moveDown(state, pages, page);
assert.equal(pendingChanges.length, 1, 'Has 1 pending change');
assert.equal(pendingChanges[0].pageId, 1);
assert.equal(pendingChanges[0].sequence, 330 * 2);
});

View file

@ -30,7 +30,7 @@ const (
// AppVersion does what it says // AppVersion does what it says
// Versioning scheme major.minor where "minor" is optional // Versioning scheme major.minor where "minor" is optional
// e.g. 1, 2, 3, 4.1, 4.2, 5, 6, 7, 7.1, 8, 9, 10, ..... 127, 127.1, 128 // e.g. 1, 2, 3, 4.1, 4.2, 5, 6, 7, 7.1, 8, 9, 10, ..... 127, 127.1, 128
AppVersion = "12.7" AppVersion = "12.8"
) )
var port, certFile, keyFile, forcePort2SSL string var port, certFile, keyFile, forcePort2SSL string