mirror of
https://github.com/documize/community.git
synced 2025-07-25 08:09:43 +02:00
commit
68107a4ea1
177 changed files with 6274 additions and 2035 deletions
10
README.md
10
README.md
|
@ -8,7 +8,7 @@ The mission is to bring software dev inspired features (refactoring, testing, li
|
|||
|
||||
## Latest version
|
||||
|
||||
v0.43.1
|
||||
v0.44.0
|
||||
|
||||
## OS Support
|
||||
|
||||
|
@ -18,7 +18,7 @@ v0.43.1
|
|||
|
||||
## Tech stack
|
||||
|
||||
- EmberJS (v2.11.2)
|
||||
- EmberJS (v2.12.0)
|
||||
- Go (v1.8)
|
||||
- MySQL (v5.7.10+) or Percona (v5.7.16-10+)
|
||||
|
||||
|
@ -28,12 +28,18 @@ v0.43.1
|
|||
- [Install for development guide](https://developers.documize.com/s/VzO9ZqMOCgABGyfW/installation/d/V16LOMucxwABhZF1/install-documize-for-development-guide)
|
||||
- [Configuration guide](https://developers.documize.com/s/VzO9ZqMOCgABGyfW/installation/d/VzSL8cVZ4QAB2B4Y/configure-documize-guide)
|
||||
|
||||
## Keycloak Integration
|
||||
|
||||
Documize provides out-of-the-box integration with [Redhat Keycloak](http://www.keycloak.org) for open source identity and access management.
|
||||
|
||||
## Auth0 Integration
|
||||
|
||||
Documize is compatible with Auth0 identity as a service.
|
||||
|
||||
[](https://auth0.com/?utm_source=oss&utm_medium=gp&utm_campaign=oss)
|
||||
|
||||
Open Source Identity and Access Management
|
||||
|
||||
## Word Conversion to HTML
|
||||
|
||||
- [Code for `wordconvert` utility](https://github.com/documize/community/tree/master/cmd/wordconvert)
|
||||
|
|
37
app/.eslintrc.js
Normal file
37
app/.eslintrc.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
ecmaVersion: 6,
|
||||
sourceType: 'module'
|
||||
},
|
||||
extends: 'eslint:recommended',
|
||||
env: {
|
||||
browser: true,
|
||||
jquery: true,
|
||||
qunit: true,
|
||||
embertest: true
|
||||
},
|
||||
rules: {
|
||||
},
|
||||
globals: {
|
||||
"$": true,
|
||||
"is": true,
|
||||
"_": true,
|
||||
"tinymce": true,
|
||||
"CodeMirror": true,
|
||||
"Drop": true,
|
||||
"Mousetrap": true,
|
||||
"Sortable": true,
|
||||
"moment": true,
|
||||
"Dropzone": true,
|
||||
"Tooltip": true,
|
||||
"server": true,
|
||||
"authenticateUser": true,
|
||||
"stubAudit": true,
|
||||
"stubUserNotification": true,
|
||||
"userLogin": true,
|
||||
"Keycloak": true,
|
||||
"Intercom": true,
|
||||
"slug": true
|
||||
}
|
||||
};
|
5
app/.gitignore
vendored
5
app/.gitignore
vendored
|
@ -1,7 +1,8 @@
|
|||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/dist-prod
|
||||
/tmp
|
||||
|
||||
# dependencies
|
||||
|
@ -13,5 +14,5 @@
|
|||
/connect.lock
|
||||
/coverage/*
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
npm-debug.log*
|
||||
testem.log
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"predef": [
|
||||
"server",
|
||||
"document",
|
||||
"window",
|
||||
"-Promise",
|
||||
"moment",
|
||||
"$",
|
||||
"jQuery",
|
||||
"_",
|
||||
"is",
|
||||
"Mousetrap",
|
||||
"CodeMirror",
|
||||
"Intercom",
|
||||
"Materialize",
|
||||
"tinymce",
|
||||
"Tether",
|
||||
"Tooltip",
|
||||
"Drop",
|
||||
"Dropzone",
|
||||
"Sortable",
|
||||
"datetimepicker",
|
||||
"Waypoint",
|
||||
"velocity"
|
||||
],
|
||||
"browser": true,
|
||||
"boss": true,
|
||||
"curly": true,
|
||||
"debug": false,
|
||||
"devel": true,
|
||||
"eqeqeq": true,
|
||||
"evil": true,
|
||||
"forin": false,
|
||||
"immed": false,
|
||||
"laxbreak": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": false,
|
||||
"nomen": false,
|
||||
"onevar": false,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"sub": true,
|
||||
"strict": false,
|
||||
"white": false,
|
||||
"eqnull": true,
|
||||
"esnext": true,
|
||||
"unused": true
|
||||
}
|
|
@ -1,21 +1,22 @@
|
|||
---
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.12"
|
||||
- "6"
|
||||
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- $HOME/.npm
|
||||
- $HOME/.cache # includes bowers cache
|
||||
|
||||
before_install:
|
||||
- export PATH=/usr/local/phantomjs-2.0.0/bin:$PATH
|
||||
- "npm config set spin false"
|
||||
- "npm install -g npm@^2"
|
||||
- npm config set spin false
|
||||
- npm install -g bower phantomjs-prebuilt
|
||||
- bower --version
|
||||
- phantomjs --version
|
||||
|
||||
install:
|
||||
- npm install -g bower
|
||||
- npm install
|
||||
- bower install
|
||||
|
||||
|
|
|
@ -21,15 +21,16 @@ const {
|
|||
} = Ember;
|
||||
|
||||
export default Base.extend({
|
||||
|
||||
ajax: service(),
|
||||
appMeta: service(),
|
||||
localStorage: service(),
|
||||
|
||||
restore(data) {
|
||||
// TODO: verify authentication data
|
||||
if (data) {
|
||||
return resolve(data);
|
||||
}
|
||||
|
||||
return reject();
|
||||
},
|
||||
|
||||
|
@ -51,16 +52,13 @@ export default Base.extend({
|
|||
return Ember.RSVP.reject("invalid");
|
||||
}
|
||||
|
||||
var headers = {
|
||||
'Authorization': 'Basic ' + encoded
|
||||
};
|
||||
let headers = { 'Authorization': 'Basic ' + encoded };
|
||||
|
||||
return this.get('ajax').post('public/authenticate', {
|
||||
headers
|
||||
});
|
||||
return this.get('ajax').post('public/authenticate', { headers });
|
||||
},
|
||||
|
||||
invalidate() {
|
||||
this.get('localStorage').clearAll();
|
||||
return resolve();
|
||||
}
|
||||
});
|
54
app/app/authenticators/keycloak.js
Normal file
54
app/app/authenticators/keycloak.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
// 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 Base from 'ember-simple-auth/authenticators/base';
|
||||
import netUtil from '../utils/net';
|
||||
|
||||
const {
|
||||
isPresent,
|
||||
RSVP: { resolve, reject },
|
||||
inject: { service }
|
||||
} = Ember;
|
||||
|
||||
export default Base.extend({
|
||||
ajax: service(),
|
||||
appMeta: service(),
|
||||
kcAuth: service(),
|
||||
localStorage: service(),
|
||||
|
||||
restore(data) {
|
||||
// TODO: verify authentication data
|
||||
if (data) {
|
||||
return resolve(data);
|
||||
}
|
||||
|
||||
return reject();
|
||||
},
|
||||
|
||||
authenticate(data) {
|
||||
data.domain = netUtil.getSubdomain();
|
||||
|
||||
if (!isPresent(data.token) || !isPresent(data.email)) {
|
||||
return Ember.RSVP.reject("invalid");
|
||||
}
|
||||
|
||||
return this.get('ajax').post('public/authenticate/keycloak', {
|
||||
data: JSON.stringify(data),
|
||||
contentType: 'json'
|
||||
});
|
||||
},
|
||||
|
||||
invalidate() {
|
||||
this.get('localStorage').clearAll();
|
||||
return this.get('kcAuth').logout();
|
||||
}
|
||||
});
|
119
app/app/components/customize/auth-settings.js
Normal file
119
app/app/components/customize/auth-settings.js
Normal file
|
@ -0,0 +1,119 @@
|
|||
// 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 constants from '../../utils/constants';
|
||||
import encoding from '../../utils/encoding';
|
||||
|
||||
const {
|
||||
computed
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
appMeta: Ember.inject.service(),
|
||||
isDocumizeProvider: computed.equal('authProvider', constants.AuthProvider.Documize),
|
||||
isKeycloakProvider: computed.equal('authProvider', constants.AuthProvider.Keycloak),
|
||||
KeycloakUrlError: computed.empty('keycloakConfig.url'),
|
||||
KeycloakRealmError: computed.empty('keycloakConfig.realm'),
|
||||
KeycloakClientIdError: computed.empty('keycloakConfig.clientId'),
|
||||
KeycloakPublicKeyError: computed.empty('keycloakConfig.publicKey'),
|
||||
KeycloakAdminUserError: computed.empty('keycloakConfig.adminUser'),
|
||||
KeycloakAdminPasswordError: computed.empty('keycloakConfig.adminPassword'),
|
||||
keycloakConfig: {
|
||||
url: '',
|
||||
realm: '',
|
||||
clientId: '',
|
||||
publicKey: '',
|
||||
adminUser: '',
|
||||
adminPassword: ''
|
||||
},
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
let provider = this.get('authProvider');
|
||||
|
||||
switch (provider) {
|
||||
case constants.AuthProvider.Documize:
|
||||
// nothing to do
|
||||
break;
|
||||
case constants.AuthProvider.Keycloak: // eslint-disable-line no-case-declarations
|
||||
let config = this.get('authConfig');
|
||||
|
||||
if (is.undefined(config) || is.null(config) || is.empty(config) ) {
|
||||
config = {};
|
||||
} else {
|
||||
config = JSON.parse(config);
|
||||
config.publicKey = encoding.Base64.decode(config.publicKey);
|
||||
}
|
||||
|
||||
this.set('keycloakConfig', config);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
onDocumize() {
|
||||
this.set('authProvider', constants.AuthProvider.Documize);
|
||||
},
|
||||
|
||||
onKeycloak() {
|
||||
this.set('authProvider', constants.AuthProvider.Keycloak);
|
||||
},
|
||||
|
||||
onSave() {
|
||||
let provider = this.get('authProvider');
|
||||
let config = this.get('authConfig');
|
||||
|
||||
switch (provider) {
|
||||
case constants.AuthProvider.Documize:
|
||||
config = {};
|
||||
break;
|
||||
case constants.AuthProvider.Keycloak:
|
||||
if (this.get('KeycloakUrlError')) {
|
||||
this.$("#keycloak-url").focus();
|
||||
return;
|
||||
}
|
||||
if (this.get('KeycloakRealmError')) {
|
||||
this.$("#keycloak-realm").focus();
|
||||
return;
|
||||
}
|
||||
if (this.get('KeycloakClientIdError')) {
|
||||
this.$("#keycloak-clientId").focus();
|
||||
return;
|
||||
}
|
||||
if (this.get('KeycloakPublicKeyError')) {
|
||||
this.$("#keycloak-publicKey").focus();
|
||||
return;
|
||||
}
|
||||
if (this.get('KeycloakAdminUserError')) {
|
||||
this.$("#keycloak-admin-user").focus();
|
||||
return;
|
||||
}
|
||||
if (this.get('KeycloakAdminPasswordError')) {
|
||||
this.$("#keycloak-admin-password").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
config = Ember.copy(this.get('keycloakConfig'));
|
||||
Ember.set(config, 'publicKey', encoding.Base64.encode(this.get('keycloakConfig.publicKey')));
|
||||
break;
|
||||
}
|
||||
|
||||
this.get('onSave')(provider, config).then(() => {
|
||||
});
|
||||
},
|
||||
|
||||
onSync() {
|
||||
this.get('onSync')();
|
||||
}
|
||||
}
|
||||
});
|
|
@ -10,8 +10,9 @@
|
|||
// https://documize.com
|
||||
|
||||
import Ember from 'ember';
|
||||
import AuthProvider from '../../mixins/auth';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
export default Ember.Component.extend(AuthProvider, {
|
||||
editUser: null,
|
||||
deleteUser: null,
|
||||
drop: null,
|
|
@ -10,6 +10,7 @@
|
|||
// https://documize.com
|
||||
|
||||
import Ember from 'ember';
|
||||
import AuthProvider from '../../mixins/auth';
|
||||
|
||||
const {
|
||||
isEmpty,
|
||||
|
@ -18,7 +19,7 @@ const {
|
|||
get
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
export default Ember.Component.extend(AuthProvider, {
|
||||
newUser: { firstname: "", lastname: "", email: "", active: true },
|
||||
firstnameEmpty: computed.empty('newUser.firstname'),
|
||||
lastnameEmpty: computed.empty('newUser.lastname'),
|
|
@ -22,18 +22,27 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
editMode: false,
|
||||
docName: '',
|
||||
docExcerpt: '',
|
||||
|
||||
hasNameError: computed.empty('docName'),
|
||||
hasExcerptError: computed.empty('docExcerpt'),
|
||||
|
||||
keyUp(e) {
|
||||
if (e.keyCode === 27) { // escape key
|
||||
this.send('onCancel');
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleEdit() {
|
||||
this.set('docName', this.get('document.name'));
|
||||
this.set('docExcerpt', this.get('document.excerpt'));
|
||||
this.set('editMode', true);
|
||||
|
||||
Ember.run.schedule('afterRender', () => {
|
||||
$('#document-name').select();
|
||||
});
|
||||
},
|
||||
|
||||
onSaveDocument() {
|
||||
onSave() {
|
||||
if (this.get('hasNameError') || this.get('hasExcerptError')) {
|
||||
return;
|
||||
}
|
||||
|
@ -46,7 +55,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
this.set('editMode', false);
|
||||
},
|
||||
|
||||
cancel() {
|
||||
onCancel() {
|
||||
this.set('editMode', false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,17 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
if (this.get('isDestroyed') || this.get('isDestroying')) {
|
||||
return;
|
||||
}
|
||||
|
||||
let page = this.get('page');
|
||||
|
||||
this.get('documentService').getPageMeta(page.get('documentId'), page.get('id')).then((meta) => {
|
||||
if (this.get('isDestroyed') || this.get('isDestroying')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set('meta', meta);
|
||||
if (this.get('toEdit') === this.get('page.id') && this.get('isEditor')) {
|
||||
this.send('onEdit');
|
||||
|
|
|
@ -23,7 +23,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
appMeta: Ember.inject.service(),
|
||||
link: Ember.inject.service(),
|
||||
hasPages: computed.notEmpty('pages'),
|
||||
newSectionName: '',
|
||||
newSectionName: 'Section',
|
||||
newSectionNameMissing: computed.empty('newSectionName'),
|
||||
newSectionLocation: '',
|
||||
beforePage: '',
|
||||
|
@ -34,7 +34,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
|
||||
this.loadBlocks();
|
||||
|
||||
Ember.run.schedule('afterRender', () => {
|
||||
Ember.run.schedule('afterRender', () => {
|
||||
let jumpTo = "#page-" + this.get('pageId');
|
||||
if (!$(jumpTo).inView()) {
|
||||
$(jumpTo).velocity("scroll", { duration: 250, offset: -100 });
|
||||
|
@ -51,13 +51,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
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});
|
||||
} });
|
||||
this.setupAddWizard();
|
||||
|
||||
let self = this;
|
||||
$(".tooltipped").each(function(i, el) {
|
||||
|
@ -67,6 +61,8 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
$('.start-section:not(.start-section-empty-state)').off('.hoverIntent');
|
||||
|
||||
this.destroyTooltips();
|
||||
},
|
||||
|
@ -105,6 +101,20 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
});
|
||||
},
|
||||
|
||||
setupAddWizard() {
|
||||
Ember.run.schedule('afterRender', () => {
|
||||
$('.start-section:not(.start-section-empty-state)').off('.hoverIntent');
|
||||
|
||||
$('.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});
|
||||
} });
|
||||
});
|
||||
},
|
||||
|
||||
addSection(model) {
|
||||
// calculate sequence of page (position in document)
|
||||
let sequence = 0;
|
||||
|
@ -172,10 +182,10 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
},
|
||||
|
||||
onSavePage(page, meta) {
|
||||
this.set('toEdit', '');
|
||||
this.attrs.onSavePage(page, meta);
|
||||
},
|
||||
|
||||
// Section wizard related
|
||||
onShowSectionWizard(page) {
|
||||
if (is.undefined(page)) {
|
||||
page = { id: '0' };
|
||||
|
@ -200,7 +210,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
}
|
||||
|
||||
$("#new-section-wizard").insertAfter(`#add-section-button-${page.id}`);
|
||||
$("#new-section-wizard").velocity("transition.slideDownIn", {duration: 300, complete:
|
||||
$("#new-section-wizard").velocity("transition.slideDownIn", { duration: 300, complete:
|
||||
function() {
|
||||
$("#new-section-name").focus();
|
||||
}});
|
||||
|
@ -209,6 +219,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
onHideSectionWizard() {
|
||||
this.set('newSectionLocation', '');
|
||||
this.set('beforePage', null);
|
||||
$("#new-section-wizard").insertAfter('#wizard-placeholder');
|
||||
$("#new-section-wizard").velocity("transition.slideUpOut", { duration: 300 });
|
||||
},
|
||||
|
||||
|
@ -251,6 +262,8 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
} else {
|
||||
this.set('toEdit', '');
|
||||
}
|
||||
|
||||
this.setupAddWizard();
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -289,12 +302,8 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
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', '');
|
||||
// }
|
||||
|
||||
this.setupAddWizard();
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ export default Ember.Component.extend({
|
|||
selectedDocuments: [],
|
||||
|
||||
emptyState: Ember.computed('documents', function() {
|
||||
return this.get('documents.length') === 0;
|
||||
}),
|
||||
return this.get('documents.length') === 0;
|
||||
}),
|
||||
|
||||
didReceiveAttrs() {
|
||||
this.set('selectedDocuments', []);
|
||||
|
|
|
@ -10,12 +10,13 @@
|
|||
// https://documize.com
|
||||
|
||||
import Ember from 'ember';
|
||||
import AuthMixin from '../../mixins/auth';
|
||||
|
||||
const {
|
||||
inject: { service }
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
export default Ember.Component.extend(AuthMixin, {
|
||||
folderService: service('folder'),
|
||||
appMeta: service(),
|
||||
users: [],
|
||||
|
@ -103,7 +104,7 @@ export default Ember.Component.extend({
|
|||
message = this.getDefaultInvitationMessage();
|
||||
}
|
||||
|
||||
this.get('permissions').forEach((permission, index) => { /* jshint ignore:line */
|
||||
this.get('permissions').forEach((permission, index) => { // eslint-disable-line no-unused-vars
|
||||
Ember.set(permission, 'canView', $("#canView-" + permission.userId).prop('checked'));
|
||||
Ember.set(permission, 'canEdit', $("#canEdit-" + permission.userId).prop('checked'));
|
||||
});
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
import Ember from 'ember';
|
||||
import NotifierMixin from '../../mixins/notifier';
|
||||
import TooltipMixin from '../../mixins/tooltip';
|
||||
import AuthMixin from '../../mixins/auth';
|
||||
|
||||
const {
|
||||
computed
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
||||
export default Ember.Component.extend(NotifierMixin, TooltipMixin, AuthMixin, {
|
||||
folderService: Ember.inject.service('folder'),
|
||||
session: Ember.inject.service(),
|
||||
appMeta: Ember.inject.service(),
|
||||
|
@ -37,7 +38,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
|||
didReceiveAttrs() {
|
||||
this.set('isFolderOwner', this.get('folder.userId') === this.get("session.user.id"));
|
||||
|
||||
let show = this.get('isFolderOwner') || this.get('hasSelectedDocuments') || this.get('folderService').get('canEditCurrentFolder');
|
||||
let show = this.get('session.authenticated') || this.get('isFolderOwner') || this.get('hasSelectedDocuments') || this.get('folderService').get('canEditCurrentFolder');
|
||||
this.set('showToolbar', show);
|
||||
|
||||
let targets = _.reject(this.get('folders'), {
|
||||
|
|
|
@ -64,7 +64,7 @@ export default Ember.Component.extend(NotifierMixin, {
|
|||
});
|
||||
|
||||
this.on("error", function (x) {
|
||||
console.log("Conversion failed for ", x.name, " obj ", x); // TODO proper error handling
|
||||
console.log("Conversion failed for ", x.name, " obj ", x); // eslint-disable-line no-console
|
||||
});
|
||||
|
||||
this.on("queuecomplete", function () {});
|
||||
|
|
|
@ -77,7 +77,7 @@ export default Ember.Component.extend(TooltipMixin, {
|
|||
self.get('pinned').updateSequence(this.toArray()).then((pins) => {
|
||||
self.set('pins', pins);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.set('sortable', sortable);
|
||||
|
|
|
@ -19,8 +19,12 @@ const {
|
|||
export default Ember.Component.extend({
|
||||
drop: null,
|
||||
busy: false,
|
||||
|
||||
mousetrap: null,
|
||||
hasNameError: computed.empty('page.title'),
|
||||
containerId: Ember.computed('page', function () {
|
||||
let page = this.get('page');
|
||||
return `base-editor-inline-container-${page.id}`;
|
||||
}),
|
||||
pageId: Ember.computed('page', function () {
|
||||
let page = this.get('page');
|
||||
return `page-editor-${page.id}`;
|
||||
|
@ -43,16 +47,20 @@ export default Ember.Component.extend({
|
|||
}),
|
||||
|
||||
didRender() {
|
||||
let self = this;
|
||||
Mousetrap.bind('esc', function () {
|
||||
self.send('onCancel');
|
||||
let msContainer = document.getElementById(this.get('containerId'));
|
||||
let mousetrap = new Mousetrap(msContainer);
|
||||
|
||||
mousetrap.bind('esc', () => {
|
||||
this.send('onCancel');
|
||||
return false;
|
||||
});
|
||||
Mousetrap.bind(['ctrl+s', 'command+s'], function () {
|
||||
self.send('onAction');
|
||||
mousetrap.bind(['ctrl+s', 'command+s'], () => {
|
||||
this.send('onAction');
|
||||
return false;
|
||||
});
|
||||
|
||||
this.set('mousetrap', mousetrap);
|
||||
|
||||
$('#' + this.get('pageId')).focus(function() {
|
||||
$(this).select();
|
||||
});
|
||||
|
@ -65,8 +73,11 @@ export default Ember.Component.extend({
|
|||
drop.destroy();
|
||||
}
|
||||
|
||||
Mousetrap.unbind('esc');
|
||||
Mousetrap.unbind(['ctrl+s', 'command+s']);
|
||||
let mousetrap = this.get('mousetrap');
|
||||
if (is.not.null(mousetrap)) {
|
||||
mousetrap.unbind('esc');
|
||||
mousetrap.unbind(['ctrl+s', 'command+s']);
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
|
|
@ -28,7 +28,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
|
||||
try {
|
||||
config = JSON.parse(this.get('meta.config'));
|
||||
} catch (e) {}
|
||||
} catch (e) {} // eslint-disable-line no-empty
|
||||
|
||||
if (is.empty(config)) {
|
||||
config = {
|
||||
|
@ -57,8 +57,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
if (response.apikey.length > 0 && response.url.length > 0 && response.username.length > 0) {
|
||||
self.send('auth');
|
||||
}
|
||||
}, function (reason) { //jshint ignore: line
|
||||
console.log(reason);
|
||||
}, function (reason) { // eslint-disable-line no-unused-vars
|
||||
self.set('waiting', false);
|
||||
if (self.get('config.userId') > 0) {
|
||||
self.send('auth');
|
||||
|
@ -96,7 +95,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
});
|
||||
});
|
||||
self.set('waiting', false);
|
||||
}, function (reason) { //jshint ignore: line
|
||||
}, function (reason) { // eslint-disable-line no-unused-vars
|
||||
self.set('workspaces', []);
|
||||
self.set('waiting', false);
|
||||
});
|
||||
|
@ -116,7 +115,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
self.set('items', response);
|
||||
self.set('config.itemCount', response.length);
|
||||
self.set('waiting', false);
|
||||
}, function (reason) { //jshint ignore: line
|
||||
}, function (reason) { // eslint-disable-line no-unused-vars
|
||||
if (self.get('isDestroyed') || self.get('isDestroying')) {
|
||||
return;
|
||||
}
|
||||
|
@ -187,7 +186,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
self.set('config.userId', response.BaseEntity.id);
|
||||
self.set('waiting', false);
|
||||
self.getWorkspaces();
|
||||
}, function (reason) { //jshint ignore: line
|
||||
}, function (reason) { // eslint-disable-line no-unused-vars
|
||||
self.set('authenticated', false);
|
||||
self.set('user', null);
|
||||
self.set('config.userId', 0);
|
||||
|
|
|
@ -56,7 +56,8 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
config.showMilestones = metaConfig.showMilestones;
|
||||
config.showIssues = metaConfig.showIssues;
|
||||
config.showCommits = metaConfig.showCommits;
|
||||
} catch (e) {}
|
||||
} catch (e) { // eslint-disable-line no-empty
|
||||
}
|
||||
|
||||
if (_.isUndefined(config.showCommits)) {
|
||||
config.showCommits = true;
|
||||
|
@ -75,24 +76,24 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
.then(function () {
|
||||
self.send('authStage2');
|
||||
}, function (error) { //jshint ignore: line
|
||||
console.log(error);
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
self.send('auth');
|
||||
});
|
||||
} else {
|
||||
if (config.userId !== self.get("session.session.authenticated.user.id")) {
|
||||
console.log("github auth wrong user ID, switching");
|
||||
console.log("github auth wrong user ID, switching"); // eslint-disable-line no-console
|
||||
self.set('config.userId', self.get("session.session.authenticated.user.id"));
|
||||
}
|
||||
self.get('sectionService').fetch(page, "checkAuth", self.get('config'))
|
||||
.then(function () {
|
||||
self.send('authStage2');
|
||||
}, function (error) { //jshint ignore: line
|
||||
console.log(error);
|
||||
}, function (error) {
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
self.send('auth'); // require auth if the db token is invalid
|
||||
});
|
||||
}
|
||||
}, function (error) { //jshint ignore: line
|
||||
console.log(error);
|
||||
}, function (error) {
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -163,11 +164,11 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
|
||||
self.set('config.lists', lists);
|
||||
self.set('busy', false);
|
||||
}, function (error) { //jshint ignore: line
|
||||
}, function (error) {
|
||||
self.set('busy', false);
|
||||
self.set('authenticated', false);
|
||||
self.showNotification("Unable to fetch repositories");
|
||||
console.log(error);
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -201,11 +202,11 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
self.set('busy', false);
|
||||
self.set('owners', owners);
|
||||
self.getOwnerLists();
|
||||
}, function (error) { //jshint ignore: line
|
||||
}, function (error) {
|
||||
self.set('busy', false);
|
||||
self.set('authenticated', false);
|
||||
self.showNotification("Unable to fetch owners");
|
||||
console.log(error);
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
});
|
||||
|
||||
},
|
||||
|
@ -253,7 +254,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
meta.set('rawBody', JSON.stringify(response));
|
||||
self.set('busy', false);
|
||||
self.attrs.onAction(page, meta);
|
||||
}, function (reason) { //jshint ignore: line
|
||||
}, function (reason) { // eslint-disable-line no-unused-vars
|
||||
self.set('busy', false);
|
||||
self.attrs.onAction(page, meta);
|
||||
});
|
||||
|
|
|
@ -28,7 +28,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
|
||||
try {
|
||||
config = JSON.parse(this.get('meta.config'));
|
||||
} catch (e) {}
|
||||
} catch (e) {} // eslint-disable-line no-empty
|
||||
|
||||
if (is.empty(config)) {
|
||||
config = {
|
||||
|
@ -90,19 +90,19 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
if (is.not.undefined(group)) {
|
||||
Ember.set(config, 'group', group);
|
||||
}
|
||||
}, function (reason) { //jshint ignore: line
|
||||
}, function (reason) {
|
||||
self.set('authenticated', false);
|
||||
self.set('waiting', false);
|
||||
self.set('config.APIToken', ''); // clear the api token
|
||||
self.displayError(reason);
|
||||
console.log("get options call failed");
|
||||
console.log("get options call failed"); // eslint-disable-line no-console
|
||||
});
|
||||
}, function (reason) { //jshint ignore: line
|
||||
}, function (reason) {
|
||||
self.set('authenticated', false);
|
||||
self.set('waiting', false);
|
||||
self.set('config.APIToken', ''); // clear the api token
|
||||
self.displayError(reason);
|
||||
console.log("auth token invalid");
|
||||
console.log("auth token invalid"); // eslint-disable-line no-console
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -176,7 +176,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
|
||||
self.set('waiting', false);
|
||||
self.attrs.onAction(page, meta);
|
||||
}, function (reason) { //jshint ignore: line
|
||||
}, function (reason) { // eslint-disable-line no-unused-vars
|
||||
self.set('authenticated', false);
|
||||
self.set('waiting', false);
|
||||
self.showNotification(`Something went wrong, try again!`);
|
||||
|
|
|
@ -43,7 +43,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
|
||||
try {
|
||||
config = JSON.parse(this.get('meta.config'));
|
||||
} catch (e) {}
|
||||
} catch (e) {} // eslint-disable-line no-empty
|
||||
|
||||
if (is.empty(config)) {
|
||||
config = {
|
||||
|
@ -77,8 +77,8 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
Trello.deauthorize();
|
||||
});
|
||||
}
|
||||
}, function (error) { //jshint ignore: line
|
||||
console.log(error);
|
||||
}, function (error) {
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -132,7 +132,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
self.set('busy', false);
|
||||
self.set('authenticated', false);
|
||||
self.showNotification("Unable to fetch board lists");
|
||||
console.log(error);
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -181,7 +181,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
Trello.members.get("me", function (user) {
|
||||
self.set('config.user', user);
|
||||
}, function (error) {
|
||||
console.log(error);
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
});
|
||||
|
||||
self.get('sectionService').fetch(page, "boards", self.get('config'))
|
||||
|
@ -193,14 +193,14 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
self.set('busy', false);
|
||||
self.set('authenticated', false);
|
||||
self.showNotification("Unable to fetch boards");
|
||||
console.log(error);
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
});
|
||||
},
|
||||
error: function (error) {
|
||||
self.set('busy', false);
|
||||
self.set('authenticated', false);
|
||||
self.showNotification("Unable to authenticate");
|
||||
console.log(error);
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -233,7 +233,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
|
|||
meta.set('rawBody', JSON.stringify(response));
|
||||
self.set('busy', false);
|
||||
self.attrs.onAction(page, meta);
|
||||
}, function (reason) { //jshint ignore: line
|
||||
}, function (reason) { // eslint-disable-line no-unused-vars
|
||||
self.set('busy', false);
|
||||
self.attrs.onAction(page, meta);
|
||||
});
|
||||
|
|
|
@ -54,16 +54,16 @@ export default Ember.Component.extend({
|
|||
}
|
||||
},
|
||||
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'}],
|
||||
{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',
|
||||
|
|
|
@ -17,7 +17,8 @@ export default Ember.Component.extend({
|
|||
prompt: null,
|
||||
optionValuePath: 'id',
|
||||
optionLabelPath: 'name',
|
||||
action: Ember.K, // action to fire on change
|
||||
action() {}, // action to fire on change
|
||||
// action: Ember.K, // action to fire on change
|
||||
|
||||
// shadow the passed-in `selection` to avoid
|
||||
// leaking changes to it via a 2-way binding
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
// https://documize.com
|
||||
|
||||
import Ember from 'ember';
|
||||
import AuthProvider from '../mixins/auth';
|
||||
|
||||
const {
|
||||
computed,
|
||||
|
@ -18,7 +19,7 @@ const {
|
|||
isPresent
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
export default Ember.Component.extend(AuthProvider, {
|
||||
password: { password: "", confirmation: "" },
|
||||
hasFirstnameError: computed.empty('model.firstname'),
|
||||
hasLastnameError: computed.empty('model.lastname'),
|
||||
|
@ -44,6 +45,10 @@ export default Ember.Component.extend({
|
|||
}
|
||||
}),
|
||||
|
||||
didReceiveAttrs() {
|
||||
this.set
|
||||
},
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
let password = this.get('password.password');
|
||||
|
|
|
@ -48,7 +48,6 @@ export default Ember.Component.extend(NotifierMixin, {
|
|||
},
|
||||
|
||||
addFolder() {
|
||||
console.log("adding folder!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,11 +34,10 @@ export function documentFileIcon(params) {
|
|||
|
||||
case "html":
|
||||
html = "html.png";
|
||||
break;
|
||||
break;
|
||||
case "css":
|
||||
html = "css.png";
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case "bat":
|
||||
case "sh":
|
||||
|
|
25
app/app/mixins/auth.js
Normal file
25
app/app/mixins/auth.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
// 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 constants from '../utils/constants';
|
||||
|
||||
export default Ember.Mixin.create({
|
||||
appMeta: Ember.inject.service(),
|
||||
isAuthProviderDocumize: true,
|
||||
IsAuthProviderKeycloak: false,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.set('isAuthProviderDocumize', this.get('appMeta.authProvider') === constants.AuthProvider.Documize);
|
||||
this.set('isAuthProviderKeycloak', this.get('appMeta.authProvider') === constants.AuthProvider.Keycloak);
|
||||
}
|
||||
});
|
|
@ -10,10 +10,27 @@
|
|||
// https://documize.com
|
||||
|
||||
import Ember from 'ember';
|
||||
import constants from '../../../utils/constants';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
appMeta: Ember.inject.service(),
|
||||
|
||||
beforeModel() {
|
||||
if (this.get('appMeta.authProvider') === constants.AuthProvider.Keycloak) {
|
||||
this.transitionTo('auth.login');
|
||||
}
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.set('model', model);
|
||||
controller.set('sayThanks', false);
|
||||
}
|
||||
},
|
||||
|
||||
activate() {
|
||||
$('body').addClass('background-color-off-white');
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
$('body').removeClass('background-color-off-white');
|
||||
}
|
||||
});
|
14
app/app/pods/auth/keycloak/controller.js
Normal file
14
app/app/pods/auth/keycloak/controller.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
// 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({});
|
61
app/app/pods/auth/keycloak/route.js
Normal file
61
app/app/pods/auth/keycloak/route.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
// 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 constants from '../../../utils/constants';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
session: Ember.inject.service(),
|
||||
appMeta: Ember.inject.service(),
|
||||
kcAuth: Ember.inject.service(),
|
||||
localStorage: Ember.inject.service(),
|
||||
queryParams: {
|
||||
mode: {
|
||||
refreshModel: true
|
||||
}
|
||||
},
|
||||
message: '',
|
||||
|
||||
beforeModel(transition) {
|
||||
return new Ember.RSVP.Promise((resolve) => {
|
||||
this.set('mode', is.not.undefined(transition.queryParams.mode) ? transition.queryParams.mode : 'reject');
|
||||
|
||||
if (this.get('mode') === 'reject' || this.get('appMeta.authProvider') !== constants.AuthProvider.Keycloak) {
|
||||
resolve();
|
||||
}
|
||||
|
||||
this.get('kcAuth').fetchProfile().then((profile) => {
|
||||
let data = this.get('kcAuth').mapProfile(profile);
|
||||
|
||||
this.get("session").authenticate('authenticator:keycloak', data).then(() => {
|
||||
this.get('audit').record("logged-in-keycloak");
|
||||
this.transitionTo('folders');
|
||||
}, (reject) => {
|
||||
this.set('message', reject.Error);
|
||||
this.set('mode', 'reject');
|
||||
resolve();
|
||||
});
|
||||
|
||||
}, (reject) => {
|
||||
this.set('mode', 'reject');
|
||||
this.set('message', reject);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
model() {
|
||||
return {
|
||||
mode: this.get('mode'),
|
||||
message: this.get('message')
|
||||
}
|
||||
}
|
||||
});
|
13
app/app/pods/auth/keycloak/template.hbs
Normal file
13
app/app/pods/auth/keycloak/template.hbs
Normal file
|
@ -0,0 +1,13 @@
|
|||
{{#if (is-equal model.mode 'login')}}
|
||||
<div class="sso-box">
|
||||
<p>Authenticating with Keycloak...</p>
|
||||
<img src="/assets/img/busy-gray.gif" />
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if (is-equal model.mode 'reject')}}
|
||||
<div class="sso-box">
|
||||
<p>Keycloak authentication failure</p>
|
||||
<p>{{model.message}}</p>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -10,39 +10,37 @@
|
|||
// https://documize.com
|
||||
|
||||
import Ember from 'ember';
|
||||
import AuthProvider from '../../../mixins/auth';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
email: "",
|
||||
password: "",
|
||||
invalidCredentials: false,
|
||||
export default Ember.Controller.extend(AuthProvider, {
|
||||
appMeta: Ember.inject.service('app-meta'),
|
||||
session: Ember.inject.service('session'),
|
||||
audit: Ember.inject.service('audit'),
|
||||
invalidCredentials: false,
|
||||
|
||||
reset() {
|
||||
this.setProperties({
|
||||
email: "",
|
||||
password: ""
|
||||
email: '',
|
||||
password: ''
|
||||
});
|
||||
|
||||
let dbhash = document.head.querySelector("[property=dbhash]").content;
|
||||
if (dbhash.length > 0 && dbhash !== "{{.DBhash}}") {
|
||||
this.transitionToRoute('setup');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
actions: {
|
||||
login() {
|
||||
let creds = this.getProperties('email', 'password');
|
||||
|
||||
this.get('session').authenticate('authenticator:documize', creds)
|
||||
.then((response) => {
|
||||
this.get('audit').record("logged-in");
|
||||
this.transitionToRoute('folders');
|
||||
return response;
|
||||
}).catch(() => {
|
||||
this.set('invalidCredentials', true);
|
||||
});
|
||||
this.get('session').authenticate('authenticator:documize', creds).then((response) => {
|
||||
this.get('audit').record("logged-in");
|
||||
this.transitionToRoute('folders');
|
||||
return response;
|
||||
}).catch(() => {
|
||||
this.set('invalidCredentials', true);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,11 +10,58 @@
|
|||
// https://documize.com
|
||||
|
||||
import Ember from 'ember';
|
||||
import constants from '../../../utils/constants';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
appMeta: Ember.inject.service(),
|
||||
kcAuth: Ember.inject.service(),
|
||||
localStorage: Ember.inject.service(),
|
||||
showLogin: false,
|
||||
|
||||
beforeModel(transition) {
|
||||
return new Ember.RSVP.Promise((resolve) => {
|
||||
let authProvider = this.get('appMeta.authProvider');
|
||||
|
||||
switch (authProvider) {
|
||||
case constants.AuthProvider.Keycloak:
|
||||
this.set('showLogin', false);
|
||||
|
||||
this.get('kcAuth').login().then(() => {
|
||||
this.transitionTo('auth.keycloak', { queryParams: { mode: 'login' }});
|
||||
resolve();
|
||||
}, (reject) => {
|
||||
transition.abort();
|
||||
console.log (reject); // eslint-disable-line no-console
|
||||
this.transitionTo('auth.keycloak', { queryParams: { mode: 'reject' }});
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
this.set('showLogin', true);
|
||||
resolve();
|
||||
break;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
model() {
|
||||
return {
|
||||
showLogin: this.get('showLogin')
|
||||
};
|
||||
},
|
||||
|
||||
setupController: function (controller, model) {
|
||||
controller.set('model', model);
|
||||
controller.reset();
|
||||
this.browser.setTitleAsPhrase("Login");
|
||||
},
|
||||
|
||||
activate() {
|
||||
$('body').addClass('background-color-off-white');
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
$('body').removeClass('background-color-off-white');
|
||||
}
|
||||
});
|
|
@ -1,23 +1,27 @@
|
|||
<div class="auth-box">
|
||||
<div class="logo">
|
||||
<img src="/assets/img/logo-color.png" title="Documize" alt="Documize" class="responsive-img" />
|
||||
{{#if model.showLogin}}
|
||||
<div class="auth-box">
|
||||
<div class="logo">
|
||||
<img src="/assets/img/logo-color.png" title="Documize" alt="Documize" class="responsive-img" />
|
||||
</div>
|
||||
<div class="login-form">
|
||||
<form id="login-form" {{action 'login' on="submit"}}>
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
{{focus-input type="email" value=email id="authEmail"}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Password</label>
|
||||
{{input type="password" value=password id="authPassword"}}
|
||||
</div>
|
||||
<div class="clearfix" />
|
||||
<div class="margin-top-10 margin-bottom-20">
|
||||
<button type="submit" class="regular-button button-blue">Sign in</button>
|
||||
<span class="{{unless invalidCredentials "hide"}} color-red margin-left-20">Invalid credentials</span>
|
||||
</div>
|
||||
{{#if isAuthProviderDocumize}}
|
||||
{{#link-to 'auth.forgot'}}Forgot your password?{{/link-to}}
|
||||
{{/if}}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-form">
|
||||
<form id="login-form" {{action 'login' on="submit"}}>
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
{{focus-input type="email" value=email id="authEmail"}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Password</label>
|
||||
{{input type="password" value=password id="authPassword"}}
|
||||
</div>
|
||||
<div class="clearfix" />
|
||||
<div class="margin-top-10 margin-bottom-20">
|
||||
<button type="submit" class="regular-button button-blue">Sign in</button>
|
||||
<span class="{{unless invalidCredentials "hide"}} color-red margin-left-20">Invalid credentials</span>
|
||||
</div>
|
||||
{{#link-to 'auth.forgot'}}Forgot your password?{{/link-to}}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -17,18 +17,19 @@ export default Ember.Route.extend({
|
|||
appMeta: Ember.inject.service(),
|
||||
|
||||
activate: function () {
|
||||
this.get('session').invalidate();
|
||||
this.audit.record("logged-in");
|
||||
this.audit.record("logged-out");
|
||||
this.audit.stop();
|
||||
|
||||
if (config.environment === 'test') {
|
||||
this.transitionTo('auth.login');
|
||||
} else {
|
||||
if (this.get("appMeta.allowAnonymousAccess")) {
|
||||
this.transitionTo('folders');
|
||||
} else {
|
||||
this.get('session').invalidate().then(() => {
|
||||
if (config.environment === 'test') {
|
||||
this.transitionTo('auth.login');
|
||||
} else {
|
||||
if (this.get("appMeta.allowAnonymousAccess")) {
|
||||
this.transitionTo('folders');
|
||||
} else {
|
||||
this.transitionTo('auth.login');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
{{outlet}}
|
||||
<div class="sso-box">
|
||||
<p>Logging out...</p>
|
||||
<img src="/assets/img/busy-gray.gif" />
|
||||
</div>
|
||||
|
|
|
@ -15,4 +15,12 @@ export default Ember.Route.extend({
|
|||
model: function (params) {
|
||||
return params.token;
|
||||
},
|
||||
|
||||
activate() {
|
||||
$('body').addClass('background-color-off-white');
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
$('body').removeClass('background-color-off-white');
|
||||
}
|
||||
});
|
|
@ -24,5 +24,13 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
|||
controller.set('serial', this.serial);
|
||||
controller.set('slug', this.slug);
|
||||
controller.set('folderId', this.folderId);
|
||||
}
|
||||
},
|
||||
|
||||
activate() {
|
||||
$('body').addClass('background-color-off-white');
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
$('body').removeClass('background-color-off-white');
|
||||
}
|
||||
});
|
|
@ -20,7 +20,6 @@ export default Ember.Route.extend({
|
|||
this.transitionTo('folders');
|
||||
}, () => {
|
||||
this.transitionTo('auth.login');
|
||||
console.log(">>>>> Documize SSO failure");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
58
app/app/pods/customize/auth/controller.js
Normal file
58
app/app/pods/customize/auth/controller.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
// 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 constants from '../../../utils/constants';
|
||||
|
||||
export default Ember.Controller.extend(NotifierMixin, {
|
||||
global: Ember.inject.service(),
|
||||
appMeta: Ember.inject.service(),
|
||||
session: Ember.inject.service(),
|
||||
|
||||
handleProviderChange(data) {
|
||||
this.get('session').logout();
|
||||
this.set('appMeta.authProvider', data.authProvider);
|
||||
this.set('appMeta.authConfig', data.authConfig);
|
||||
window.location.href= '/';
|
||||
},
|
||||
|
||||
actions: {
|
||||
onSave(provider, config) {
|
||||
if(this.get('session.isGlobalAdmin')) {
|
||||
let data = { authProvider: provider, authConfig: JSON.stringify(config) };
|
||||
|
||||
return this.get('global').saveAuthConfig(data).then(() => {
|
||||
this.showNotification('Saved');
|
||||
|
||||
if (provider !== this.get('appMeta.authProvider')) {
|
||||
if (provider === constants.AuthProvider.Keycloak) {
|
||||
this.get('global').syncExternalUsers().then(() => {
|
||||
this.handleProviderChange(data);
|
||||
});
|
||||
} else {
|
||||
this.handleProviderChange(data);
|
||||
}
|
||||
} else {
|
||||
this.set('appMeta.authProvider', provider);
|
||||
this.set('appMeta.authConfig', config);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onSync() {
|
||||
return this.get('global').syncExternalUsers().then((response) => {
|
||||
this.showNotification(response.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
48
app/app/pods/customize/auth/route.js
Normal file
48
app/app/pods/customize/auth/route.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
// 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';
|
||||
import constants from '../../../utils/constants';
|
||||
|
||||
export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
||||
appMeta: Ember.inject.service(),
|
||||
session: Ember.inject.service(),
|
||||
global: Ember.inject.service(),
|
||||
|
||||
beforeModel() {
|
||||
if (!this.get("session.isGlobalAdmin")) {
|
||||
this.transitionTo('auth.login');
|
||||
}
|
||||
},
|
||||
|
||||
model() {
|
||||
let data = {
|
||||
authProvider: this.get('appMeta.authProvider'),
|
||||
authConfig: null,
|
||||
};
|
||||
|
||||
switch (data.authProvider) {
|
||||
case constants.AuthProvider.Keycloak:
|
||||
data.authConfig = this.get('appMeta.authConfig');
|
||||
break;
|
||||
case constants.AuthProvider.Documize:
|
||||
data.authConfig = '';
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
activate() {
|
||||
document.title = "Authentication | Documize";
|
||||
}
|
||||
});
|
1
app/app/pods/customize/auth/template.hbs
Normal file
1
app/app/pods/customize/auth/template.hbs
Normal file
|
@ -0,0 +1 @@
|
|||
{{customize/auth-settings authProvider=model.authProvider authConfig=model.authConfig onSave=(action 'onSave') onSync=(action 'onSync')}}
|
|
@ -1 +1 @@
|
|||
{{general-settings model=model save=(action 'save')}}
|
||||
{{customize/general-settings model=model save=(action 'save')}}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{{global-settings model=model saveSMTP=(action 'saveSMTP') saveLicense=(action 'saveLicense')}}
|
||||
{{customize/global-settings model=model saveSMTP=(action 'saveSMTP') saveLicense=(action 'saveLicense')}}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
{{#link-to 'customize.users' activeClass='selected' class="option" tagName="li"}}Users{{/link-to}}
|
||||
{{#if session.isGlobalAdmin}}
|
||||
{{#link-to 'customize.global' activeClass='selected' class="option" tagName="li"}}Global{{/link-to}}
|
||||
{{#link-to 'customize.auth' activeClass='selected' class="option" tagName="li"}}Authentication{{/link-to}}
|
||||
{{/if}}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -11,9 +11,12 @@
|
|||
|
||||
import Ember from 'ember';
|
||||
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
|
||||
import constants from '../../../utils/constants';
|
||||
|
||||
export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
||||
userService: Ember.inject.service('user'),
|
||||
global: Ember.inject.service('global'),
|
||||
appMeta: Ember.inject.service(),
|
||||
|
||||
beforeModel: function () {
|
||||
if (!this.session.isAdmin) {
|
||||
|
@ -21,8 +24,20 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
|||
}
|
||||
},
|
||||
|
||||
model: function () {
|
||||
return this.get('userService').getAll();
|
||||
model() {
|
||||
return new Ember.RSVP.Promise((resolve) => {
|
||||
if (this.get('appMeta.authProvider') == constants.AuthProvider.Keycloak) {
|
||||
this.get('global').syncExternalUsers().then(() => {
|
||||
this.get('userService').getComplete().then((users) =>{
|
||||
resolve(users);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.get('userService').getComplete().then((users) =>{
|
||||
resolve(users);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
activate: function () {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{user-settings add=(action 'add')}}
|
||||
{{customize/user-settings add=(action 'add')}}
|
||||
|
||||
<div class="clearfix" />
|
||||
|
||||
{{settings/user-list users=model onDelete=(action "onDelete") onSave=(action "onSave") onPassword=(action "onPassword")}}
|
||||
{{customize/user-list users=model onDelete=(action "onDelete") onSave=(action "onSave") onPassword=(action "onPassword")}}
|
||||
|
|
|
@ -20,8 +20,8 @@ export default Ember.Controller.extend(NotifierMixin, {
|
|||
pages: [],
|
||||
toggled: false,
|
||||
queryParams: ['pageId', 'tab'],
|
||||
pageId: '',
|
||||
tab: 'index',
|
||||
pageId: '',
|
||||
tab: 'index',
|
||||
|
||||
actions: {
|
||||
toggleSidebar() {
|
||||
|
@ -113,11 +113,7 @@ export default Ember.Controller.extend(NotifierMixin, {
|
|||
}
|
||||
|
||||
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'));
|
||||
this.get('target.router').refresh();
|
||||
});
|
||||
} else {
|
||||
// page delete followed by re-leveling child pages
|
||||
|
|
|
@ -65,8 +65,6 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
|||
|
||||
actions: {
|
||||
error(error /*, transition*/ ) {
|
||||
console.log(error);
|
||||
|
||||
if (error) {
|
||||
this.transitionTo('/not-found');
|
||||
return false;
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
|
||||
{{#layout/zone-content}}
|
||||
{{folder/folder-toolbar folders=model.folders folder=model.folder hasSelectedDocuments=hasSelectedDocuments onDeleteDocument=(action
|
||||
'onDeleteDocument') onMoveDocument=(action 'onMoveDocument')}} {{folder/documents-list documents=model.documents folder=model.folder
|
||||
isFolderOwner=isFolderOwner onDocumentsChecked=(action 'onDocumentsChecked') }}
|
||||
'onDeleteDocument') onMoveDocument=(action 'onMoveDocument')}}
|
||||
{{folder/documents-list documents=model.documents folder=model.folder isFolderOwner=isFolderOwner onDocumentsChecked=(action 'onDocumentsChecked') }}
|
||||
{{/layout/zone-content}}
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
// https://documize.com
|
||||
|
||||
import Ember from 'ember';
|
||||
import AuthMixin from '../../mixins/auth';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
export default Ember.Controller.extend(AuthMixin, {
|
||||
tabGeneral: false,
|
||||
tabShare: false,
|
||||
tabPermissions: false,
|
||||
|
|
|
@ -81,7 +81,7 @@ export default Ember.Route.extend(NotifierMixin, {
|
|||
folderPermissions.pushObject(u);
|
||||
|
||||
this.get('folderService').getPermissions(model.id).then((permissions) => {
|
||||
permissions.forEach((permission, index) => { /* jshint ignore:line */
|
||||
permissions.forEach((permission, index) => { // eslint-disable-line no-unused-vars
|
||||
var folderPermission = folderPermissions.findBy('userId', permission.get('userId'));
|
||||
if (is.not.undefined(folderPermission)) {
|
||||
Ember.setProperties(folderPermission, {
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
<div class="sidebar-menu">
|
||||
<ul class="options">
|
||||
<li class="option {{if tabGeneral "selected"}}" {{action 'selectTab' 'tabGeneral'}}>General</li>
|
||||
<li class="option {{if tabShare "selected"}}" {{action 'selectTab' 'tabShare'}}>Share</li>
|
||||
{{#if isAuthProviderDocumize}}
|
||||
<li class="option {{if tabShare "selected"}}" {{action 'selectTab' 'tabShare'}}>Share</li>
|
||||
{{/if}}
|
||||
<li class="option {{if tabPermissions "selected"}}" {{action 'selectTab' 'tabPermissions'}}>Permissions</li>
|
||||
<li class="option {{if tabDelete "selected"}}" {{action 'selectTab' 'tabDelete'}}>Delete</li>
|
||||
</ul>
|
||||
|
|
|
@ -26,9 +26,8 @@ export default Ember.Controller.extend(NotifierMixin, {
|
|||
}).then(() => {
|
||||
var credentials = Encoding.Base64.encode(":" + this.model.email + ":" + this.model.password);
|
||||
window.location.href = "/auth/sso/" + encodeURIComponent(credentials);
|
||||
}).catch((error) => {
|
||||
}).catch((error) => { // eslint-disable-line no-unused-vars
|
||||
// TODO notify user of the error within the GUI
|
||||
console.log("Something went wrong attempting database creation, see server log: " + error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,18 +58,28 @@ export default Router.map(function () {
|
|||
this.route('global', {
|
||||
path: 'global'
|
||||
});
|
||||
this.route('auth', {
|
||||
path: 'auth'
|
||||
});
|
||||
});
|
||||
|
||||
this.route('setup', {
|
||||
path: 'setup'
|
||||
});
|
||||
|
||||
this.route('secure', {
|
||||
path: 'secure/:token'
|
||||
});
|
||||
|
||||
this.route('auth', {
|
||||
path: 'auth'
|
||||
}, function () {
|
||||
this.route('sso', {
|
||||
path: 'sso/:token'
|
||||
});
|
||||
this.route('keycloak', {
|
||||
path: 'keycloak'
|
||||
});
|
||||
this.route('login', {
|
||||
path: 'login'
|
||||
});
|
||||
|
|
|
@ -24,8 +24,12 @@ export default Ember.Route.extend(ApplicationRouteMixin, TooltipMixin, {
|
|||
pinned: service(),
|
||||
|
||||
beforeModel(transition) {
|
||||
this._super(...arguments);
|
||||
|
||||
return this.get('appMeta').boot(transition.targetName).then(data => {
|
||||
if (this.get('session.session.authenticator') !== "authenticator:documize" && data.allowAnonymousAccess) {
|
||||
if (this.get('session.session.authenticator') !== "authenticator:documize" &&
|
||||
this.get('session.session.authenticator') !== "authenticator:keycloak" &&
|
||||
data.allowAnonymousAccess) {
|
||||
return this.get('session').authenticate('authenticator:anonymous', data);
|
||||
}
|
||||
|
||||
|
@ -41,8 +45,8 @@ export default Ember.Route.extend(ApplicationRouteMixin, TooltipMixin, {
|
|||
|
||||
error(error, transition) {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
console.log(transition);
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
console.log(transition); // eslint-disable-line no-console
|
||||
|
||||
if (netUtil.isAjaxAccessError(error)) {
|
||||
localStorage.clear();
|
||||
|
@ -50,8 +54,7 @@ export default Ember.Route.extend(ApplicationRouteMixin, TooltipMixin, {
|
|||
}
|
||||
}
|
||||
|
||||
// Return true to bubble this event to any parent route.
|
||||
return true;
|
||||
return true; // bubble this event to any parent route
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
import Ember from 'ember';
|
||||
import config from '../config/environment';
|
||||
import constants from '../utils/constants';
|
||||
|
||||
const {
|
||||
String: { htmlSafe },
|
||||
|
@ -21,7 +22,7 @@ const {
|
|||
export default Ember.Service.extend({
|
||||
ajax: service(),
|
||||
localStorage: service(),
|
||||
|
||||
kcAuth: service(),
|
||||
endpoint: `${config.apiHost}/${config.apiNamespace}`,
|
||||
orgId: '',
|
||||
title: '',
|
||||
|
@ -30,6 +31,8 @@ export default Ember.Service.extend({
|
|||
edition: 'Community',
|
||||
valid: true,
|
||||
allowAnonymousAccess: false,
|
||||
authProvider: constants.AuthProvider.Documize,
|
||||
authConfig: null,
|
||||
setupMode: false,
|
||||
|
||||
invalidLicense() {
|
||||
|
@ -40,7 +43,7 @@ export default Ember.Service.extend({
|
|||
return [this.get('endpoint'), endpoint].join('/');
|
||||
},
|
||||
|
||||
boot(requestedUrl) { // jshint ignore:line
|
||||
boot(requestedUrl) { // eslint-disable-line no-unused-vars
|
||||
let dbhash;
|
||||
if (is.not.null(document.head.querySelector("[property=dbhash]"))) {
|
||||
dbhash = document.head.querySelector("[property=dbhash]").content;
|
||||
|
@ -59,6 +62,18 @@ export default Ember.Service.extend({
|
|||
return resolve(this);
|
||||
}
|
||||
|
||||
if (requestedUrl === 'secure') {
|
||||
this.setProperties({
|
||||
title: htmlSafe("Secure document viewing"),
|
||||
allowAnonymousAccess: true,
|
||||
setupMode: true
|
||||
});
|
||||
|
||||
this.get('localStorage').clearAll();
|
||||
|
||||
return resolve(this);
|
||||
}
|
||||
|
||||
return this.get('ajax').request('public/meta').then((response) => {
|
||||
this.setProperties(response);
|
||||
return response;
|
||||
|
|
|
@ -63,5 +63,25 @@ export default Ember.Service.extend({
|
|||
data: license
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Saves auth config for Documize instance.
|
||||
saveAuthConfig(config) {
|
||||
if(this.get('sessionService.isGlobalAdmin')) {
|
||||
return this.get('ajax').request(`global/auth`, {
|
||||
method: 'PUT',
|
||||
data: JSON.stringify(config)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
syncExternalUsers() {
|
||||
if(this.get('sessionService.isGlobalAdmin')) {
|
||||
return this.get('ajax').request(`users/sync`, {
|
||||
method: 'GET'
|
||||
}).then((response) => {
|
||||
return response;
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
106
app/app/services/kc-auth.js
Normal file
106
app/app/services/kc-auth.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
// 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 netUtil from '../utils/net';
|
||||
|
||||
const {
|
||||
inject: { service }
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Service.extend({
|
||||
sessionService: service('session'),
|
||||
audit: service(),
|
||||
ajax: service(),
|
||||
appMeta: service(),
|
||||
keycloak: null,
|
||||
config: {},
|
||||
|
||||
boot() {
|
||||
return new Ember.RSVP.Promise((resolve, reject) => {
|
||||
if (is.not.undefined(this.get('keycloak')) && is.not.null(this.get('keycloak')) ) {
|
||||
resolve(this.get('keycloak'));
|
||||
return;
|
||||
}
|
||||
|
||||
let keycloak = new Keycloak(JSON.parse(this.get('appMeta.authConfig')));
|
||||
this.set('keycloak', keycloak);
|
||||
|
||||
keycloak.onTokenExpired = function () {
|
||||
keycloak.clearToken();
|
||||
};
|
||||
|
||||
keycloak.onAuthRefreshError = function () {
|
||||
keycloak.clearToken();
|
||||
};
|
||||
|
||||
this.get('keycloak').init().success(() => {
|
||||
this.get('audit').record("initialized-keycloak");
|
||||
resolve(this.get('keycloak'));
|
||||
}).error((err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
login() {
|
||||
return new Ember.RSVP.Promise((resolve, reject) => {
|
||||
this.boot().then((keycloak) => {
|
||||
let url = netUtil.getAppUrl(netUtil.getSubdomain()) + '/auth/keycloak?mode=login';
|
||||
|
||||
keycloak.login({redirectUri: url}).success(() => {
|
||||
return resolve();
|
||||
}).error(() => {
|
||||
return reject(new Error('login failed'));
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
logout() {
|
||||
return new Ember.RSVP.Promise((resolve, reject) => {
|
||||
this.boot().then((keycloak) => {
|
||||
keycloak.logout(JSON.parse(this.get('appMeta.authConfig'))).success(() => {
|
||||
this.get('keycloak').clearToken();
|
||||
resolve();
|
||||
}).error((error) => {
|
||||
this.get('keycloak').clearToken();
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
fetchProfile() {
|
||||
return new Ember.RSVP.Promise((resolve, reject) => {
|
||||
this.boot().then((keycloak) => {
|
||||
keycloak.loadUserProfile().success((profile) => {
|
||||
resolve(profile);
|
||||
}).error((err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
mapProfile(profile) {
|
||||
return {
|
||||
domain: '',
|
||||
token: this.get('keycloak').token,
|
||||
remoteId: is.null(profile.id) || is.undefined(profile.id) ? profile.email: profile.id,
|
||||
email: is.null(profile.email) || is.undefined(profile.email) ? '': profile.email,
|
||||
username: is.null(profile.username) || is.undefined(profile.username) ? '': profile.username,
|
||||
firstname: is.null(profile.firstName) || is.undefined(profile.firstName) ? profile.username: profile.firstName,
|
||||
lastname: is.null(profile.lastName) || is.undefined(profile.lastName) ? profile.username: profile.lastName,
|
||||
enabled: is.null(profile.enabled) || is.undefined(profile.enabled) ? true: profile.enabled
|
||||
};
|
||||
}
|
||||
});
|
|
@ -13,14 +13,14 @@ import Ember from 'ember';
|
|||
|
||||
export default Ember.Service.extend({
|
||||
action: function(entry) {
|
||||
console.log(entry);
|
||||
console.log(entry); // eslint-disable-line no-console
|
||||
},
|
||||
|
||||
error: function(entry) {
|
||||
console.log(entry);
|
||||
console.log(entry); // eslint-disable-line no-console
|
||||
},
|
||||
|
||||
info: function(entry) {
|
||||
console.log(entry);
|
||||
console.log(entry); // eslint-disable-line no-console
|
||||
}
|
||||
});
|
|
@ -21,7 +21,9 @@ export default SimpleAuthSession.extend({
|
|||
ajax: service(),
|
||||
appMeta: service(),
|
||||
store: service(),
|
||||
|
||||
localStorage: service(),
|
||||
folderPermissions: null,
|
||||
currentFolder: null,
|
||||
isMac: false,
|
||||
isMobile: false,
|
||||
authenticated: computed('user.id', function () {
|
||||
|
@ -40,7 +42,7 @@ export default SimpleAuthSession.extend({
|
|||
return data.get('global');
|
||||
}),
|
||||
|
||||
init: function () {
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.set('isMac', is.mac());
|
||||
|
@ -55,6 +57,7 @@ export default SimpleAuthSession.extend({
|
|||
}
|
||||
}),
|
||||
|
||||
folderPermissions: null,
|
||||
currentFolder: null
|
||||
logout() {
|
||||
this.get('localStorage').clearAll();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -46,9 +46,9 @@ export default Ember.Service.extend({
|
|||
});
|
||||
},
|
||||
|
||||
// Returns all users for organization.
|
||||
// Returns all active users for organization.
|
||||
getAll() {
|
||||
return this.get('ajax').request(`users`).then((response) => {
|
||||
return this.get('ajax').request(`users?active=1`).then((response) => {
|
||||
return response.map((obj) => {
|
||||
let data = this.get('store').normalize('user', obj);
|
||||
return this.get('store').push(data);
|
||||
|
@ -56,6 +56,17 @@ export default Ember.Service.extend({
|
|||
});
|
||||
},
|
||||
|
||||
// Returns all active and inactive users for organization.
|
||||
getComplete() {
|
||||
return this.get('ajax').request(`users?active=0`).then((response) => {
|
||||
return response.map((obj) => {
|
||||
let data = this.get('store').normalize('user', obj);
|
||||
return this.get('store').push(data);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// Returns all users that can see folder.
|
||||
getFolderUsers(folderId) {
|
||||
let url = `users/folder/${folderId}`;
|
||||
|
|
|
@ -62,5 +62,11 @@
|
|||
font-size: 1.1rem;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.document-sidebar-form-wrapper {
|
||||
padding: 20px;
|
||||
border: 1px solid $color-stroke;
|
||||
@include border-radius(3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
padding: 25px 50px;
|
||||
box-shadow: 0 0 0 0.75pt $color-stroke,0 0 3pt 0.75pt $color-stroke;
|
||||
background-color: $color-white;
|
||||
overflow-x: scroll;
|
||||
|
||||
&:hover {
|
||||
.page-title {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
.onboarding-container
|
||||
{
|
||||
.onboarding-container {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
color: $color-off-black;
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
}
|
||||
|
||||
.round-button-mono {
|
||||
@extend .no-select;
|
||||
@include ease-in();
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
@ -52,9 +54,8 @@
|
|||
vertical-align: middle;
|
||||
border: 1px solid $color-stroke;
|
||||
text-align: center;
|
||||
@extend .no-select;
|
||||
@include ease-in();
|
||||
font-size: 1.2rem;
|
||||
background-color: transparent;
|
||||
|
||||
&:hover {
|
||||
@extend .z-depth-tiny;
|
||||
|
|
53
app/app/templates/components/customize/auth-settings.hbs
Normal file
53
app/app/templates/components/customize/auth-settings.hbs
Normal file
|
@ -0,0 +1,53 @@
|
|||
<form class="form-bordered">
|
||||
<div class="form-header">
|
||||
<div class="title">Authentication</div>
|
||||
<div class="tip">Determine the method for user authentication</div>
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Provider</label>
|
||||
<div class="tip">External authentication servers, services must be accessible from the server running this Documize instance</div>
|
||||
{{#ui/ui-radio selected=isDocumizeProvider onClick=(action 'onDocumize')}}Documize — email/password{{/ui/ui-radio}}
|
||||
{{#ui/ui-radio selected=isKeycloakProvider onClick=(action 'onKeycloak')}}Keycloak — bring your own authentication server{{/ui/ui-radio}}
|
||||
</div>
|
||||
|
||||
{{#if isKeycloakProvider}}
|
||||
<div class="form-header">
|
||||
<div class="title">Keycloak Configuration</div>
|
||||
<div class="tip">Connection parameters — create a documize user in Master realm with 'manage-users' role against target realm</div>
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Keycloak Server URL</label>
|
||||
<div class="tip">e.g. http://localhost:8888/auth</div>
|
||||
{{focus-input id="keycloak-url" type="text" value=keycloakConfig.url class=(if KeycloakUrlError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Keycloak Realm</label>
|
||||
<div class="tip">e.g. main</div>
|
||||
{{input id="keycloak-realm" type="text" value=keycloakConfig.realm class=(if keycloakRealmError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Keycloak OIDC Client ID</label>
|
||||
<div class="tip">e.g. account</div>
|
||||
{{input id="keycloak-clientId" type="text" value=keycloakConfig.clientId class=(if KeycloakClientIdError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Keycloak Realm Public Key</label>
|
||||
<div class="tip">Copy the RSA public key from Realm Settings → Keys</div>
|
||||
{{textarea id="keycloak-publicKey" type="text" value=keycloakConfig.publicKey rows=7 class=(if KeycloakPublicKeyError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Keycloak Username</label>
|
||||
<div class="tip">Used to connect with Keycloak and sync users with Documize</div>
|
||||
{{input id="keycloak-admin-user" type="text" value=keycloakConfig.adminUser class=(if KeycloakAdminUserError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Keycloak Password</label>
|
||||
<div class="tip">Used to connect with Keycloak and sync users with Documize</div>
|
||||
{{input id="keycloak-admin-password" type="password" value=keycloakConfig.adminPassword class=(if KeycloakAdminPasswordError 'error')}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="regular-button button-blue" {{action 'onSave'}}>save</div>
|
||||
<div class="button-gap" />
|
||||
<div class="regular-button button-green" {{action 'onSync'}}>sync users</div>
|
||||
</form>
|
|
@ -91,22 +91,24 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="input-control">
|
||||
<label>Password</label>
|
||||
<div class="tip">Optional new password</div>
|
||||
{{input id="edit-password" type="password" value=password.password}}
|
||||
{{#if isAuthProviderDocumize}}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="input-control">
|
||||
<label>Password</label>
|
||||
<div class="tip">Optional new password</div>
|
||||
{{input id="edit-password" type="password" value=password.password}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="input-control">
|
||||
<label>Confirm Password</label>
|
||||
<div class="tip">Confirm new password</div>
|
||||
{{input id="edit-confirmPassword" type="password" value=password.confirmation}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="input-control">
|
||||
<label>Confirm Password</label>
|
||||
<div class="tip">Confirm new password</div>
|
||||
{{input id="edit-confirmPassword" type="password" value=password.confirmation}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</form>
|
||||
</div>
|
||||
<div class="actions">
|
21
app/app/templates/components/customize/user-settings.hbs
Normal file
21
app/app/templates/components/customize/user-settings.hbs
Normal file
|
@ -0,0 +1,21 @@
|
|||
{{#if isAuthProviderDocumize}}
|
||||
<form class="form-bordered">
|
||||
<div class="form-header">
|
||||
<div class="title">Add user</div>
|
||||
<div class="tip">New users receive an invitation email with a random password</div>
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Firstname</label>
|
||||
{{focus-input id="newUserFirstname" type="text" value=newUser.firstname class=(if hasFirstnameEmptyError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Lastname</label>
|
||||
{{input id="newUserLastname" type="text" value=newUser.lastname class=(if hasLastnameEmptyError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
{{input id="newUserEmail" type="text" value=newUser.email class=(if hasEmailEmptyError 'error')}}
|
||||
</div>
|
||||
<div class="regular-button button-blue" {{ action 'add' }}>Add</div>
|
||||
</form>
|
||||
{{/if}}
|
|
@ -4,20 +4,22 @@
|
|||
<div class="doc-excerpt">{{document.excerpt}}</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="edit-document-heading">
|
||||
<div class="input-inline input-transparent edit-doc-title">
|
||||
{{focus-input id="document-name" type="text" value=docName class=(if hasNameError 'error-inline') placeholder="Name" autocomplete="off"}}
|
||||
</div>
|
||||
<div class="input-inline input-transparent edit-doc-excerpt">
|
||||
{{input id="document-excerpt" type="text" value=docExcerpt class=(if hasExcerptError 'error-inline') placeholder="Excerpt" autocomplete="off"}}
|
||||
</div>
|
||||
<div>
|
||||
<div class="round-button-mono" {{action 'onSaveDocument'}}>
|
||||
<i class="material-icons color-green">check</i>
|
||||
<form {{action "onSave" on="submit"}}>
|
||||
<div class="edit-document-heading">
|
||||
<div class="input-inline input-transparent edit-doc-title">
|
||||
{{focus-input id="document-name" type="text" value=docName class=(if hasNameError 'error-inline') placeholder="Name" autocomplete="off"}}
|
||||
</div>
|
||||
<div class="round-button-mono" {{action 'cancel'}}>
|
||||
<i class="material-icons color-gray">close</i>
|
||||
<div class="input-inline input-transparent edit-doc-excerpt">
|
||||
{{input id="document-excerpt" type="text" value=docExcerpt class=(if hasExcerptError 'error-inline') placeholder="Excerpt" autocomplete="off"}}
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class="round-button-mono" {{action 'onSave'}}>
|
||||
<i class="material-icons color-green">check</i>
|
||||
</button>
|
||||
<div class="round-button-mono" {{action 'onCancel'}}>
|
||||
<i class="material-icons color-gray">close</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{{/unless}}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<div class="document-view">
|
||||
|
||||
{{#if hasPages}}
|
||||
{{#each pages key="id" as |page index|}}
|
||||
{{#if isEditor}}
|
||||
|
@ -47,6 +48,8 @@
|
|||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<div id="wizard-placeholder" class="hide margin-top-50" />
|
||||
|
||||
<div id="new-section-wizard" class="new-section-wizard">
|
||||
<div class="input-inline input-transparent pull-left width-80">
|
||||
{{input type="text" id="new-section-name" value=newSectionName class=(if newSectionNameMissing 'section-name error-inline' 'section-name') placeholder="Name" autocomplete="off"}}
|
||||
|
@ -94,4 +97,5 @@
|
|||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<p>Are you sure you want to delete <span class="bold">{{page.title}}?</span></p>
|
||||
<p>
|
||||
{{input type="checkbox" id=checkId class="margin-left-20" checked=deleteChildren}}
|
||||
<label for="{{checkId}}"> Delete child pages</label>
|
||||
<label for="{{checkId}}"> Delete child sections</label>
|
||||
</p>
|
||||
{{/dropdown-dialog}}
|
||||
{{#dropdown-dialog id=publishDialogId target=publishButtonId position="bottom right" button="Publish" color="flat-green" focusOn=blockTitleId onAction=(action 'onSavePageAsBlock')}}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<p>Are you sure you want to delete <span class="bold">{{page.title}}?</span></p>
|
||||
<p>
|
||||
{{input type="checkbox" id=checkId class="margin-left-20" checked=deleteChildren}}
|
||||
<label for="{{checkId}}"> Delete child pages</label>
|
||||
<label for="{{checkId}}"> Delete child sections</label>
|
||||
</p>
|
||||
{{/dropdown-dialog}}
|
||||
{{#dropdown-dialog id=publishDialogId target=publishButtonId position="bottom right" button="Publish" color="flat-green" focusOn=blockTitleId onAction=(action 'onSavePageAsBlock')}}
|
||||
|
|
|
@ -5,18 +5,12 @@
|
|||
</div>
|
||||
<div class="actions">
|
||||
{{#if showCancel}}
|
||||
<div class="flat-button" {{action 'onCancel'}}>
|
||||
cancel
|
||||
</div>
|
||||
<div class="flat-button" {{action 'onCancel'}}>cancel</div>
|
||||
{{/if}}
|
||||
{{#if hasSecondButton}}
|
||||
<div class="flat-button {{color2}}" {{action 'onAction2'}}>
|
||||
{{button2}}
|
||||
</div>
|
||||
<div class="flat-button {{color2}}" {{action 'onAction2'}}>{{button2}}</div>
|
||||
{{/if}}
|
||||
<div class="flat-button {{color}} dropdown-dialog-action-button" {{action 'onAction'}}>
|
||||
{{button}}
|
||||
</div>
|
||||
<div class="flat-button {{color}} dropdown-dialog-action-button" {{action 'onAction'}}>{{button}}</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</form>
|
||||
|
|
|
@ -43,11 +43,19 @@
|
|||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if isFolderOwner}}
|
||||
{{#link-to 'settings' folder.id folder.slug (query-params tab="tabShare")}}
|
||||
<div class="round-button-mono" id="folder-share-button" data-tooltip="Share" data-tooltip-position="top center">
|
||||
<i class="material-icons color-gray">share</i>
|
||||
</div>
|
||||
{{/link-to}}
|
||||
{{#if isAuthProviderDocumize}}
|
||||
{{#link-to 'settings' folder.id folder.slug (query-params tab="tabShare")}}
|
||||
<div class="round-button-mono" id="folder-share-button" data-tooltip="Share" data-tooltip-position="top center">
|
||||
<i class="material-icons color-gray">share</i>
|
||||
</div>
|
||||
{{/link-to}}
|
||||
{{else}}
|
||||
{{#link-to 'settings' folder.id folder.slug (query-params tab="tabPermissions")}}
|
||||
<div class="round-button-mono" id="folder-share-button" data-tooltip="Share" data-tooltip-position="top center">
|
||||
<i class="material-icons color-gray">share</i>
|
||||
</div>
|
||||
{{/link-to}}
|
||||
{{/if}}
|
||||
<div class="button-gap"></div>
|
||||
{{#link-to 'settings' folder.id folder.slug}}
|
||||
<div class="round-button-mono" id="folder-settings-button" data-tooltip="Settings" data-tooltip-position="top center">
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
<img class="logo" src="/assets/img/logo-color.png"/>
|
||||
|
||||
<div class="stage-1">
|
||||
<h2>Documize Sign-up</h2>
|
||||
<p>Let's set up your account</p>
|
||||
<div class="input-control">
|
||||
<label>Firstname</label>
|
||||
|
@ -13,11 +12,11 @@
|
|||
</div>
|
||||
<div class="input-control">
|
||||
<label>Lastname</label>
|
||||
<div class="tip">To customize the app for you</div>
|
||||
<div class="tip">What the government calls you</div>
|
||||
<input id="stage-1-lastname" type="text" value="" />
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<div id="stage-1-next" class="regular-button button-green">Next ›</div>
|
||||
<div id="stage-1-next" class="regular-button button-green">Next →</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -34,7 +33,7 @@
|
|||
<input id="stage-2-password-confirm" type="password" value="" />
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<div id="stage-2-next" class="regular-button button-green">Sign In ›</div>
|
||||
<div id="stage-2-next" class="regular-button button-green">Sign In →</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="document-editor {{if blockMode 'document-editor-full'}}">
|
||||
<div id={{containerId}} class="document-editor {{if blockMode 'document-editor-full'}}">
|
||||
<div class="toolbar">
|
||||
<div class="buttons pull-right">
|
||||
{{#if busy}}
|
||||
|
|
|
@ -15,15 +15,17 @@
|
|||
<label>Email</label>
|
||||
{{input id="email" type="text" value=model.email class=(if hasEmailError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Password</label>
|
||||
<div class="tip">Optional change your password</div>
|
||||
{{input id="password" type="password" value=password.password class=hasPasswordError}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Confirm Password</label>
|
||||
<div class="tip">Confirm your new password</div>
|
||||
{{input id="confirmPassword" type="password" value=password.confirmation class=hasConfirmPasswordError}}
|
||||
</div>
|
||||
{{#if isAuthProviderDocumize}}
|
||||
<div class="input-control">
|
||||
<label>Password</label>
|
||||
<div class="tip">Optional change your password</div>
|
||||
{{input id="password" type="password" value=password.password class=hasPasswordError}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Confirm Password</label>
|
||||
<div class="tip">Confirm your new password</div>
|
||||
{{input id="confirmPassword" type="password" value=password.confirmation class=hasConfirmPasswordError}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="regular-button button-blue" {{ action 'save' }}>save</div>
|
||||
</div>
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
<form class="form-bordered">
|
||||
<div class="form-header">
|
||||
<div class="title">Add user</div>
|
||||
<div class="tip">New users receive an invitation email with a random password</div>
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Firstname</label>
|
||||
{{focus-input id="newUserFirstname" type="text" value=newUser.firstname class=(if hasFirstnameEmptyError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Lastname</label>
|
||||
{{input id="newUserLastname" type="text" value=newUser.lastname class=(if hasLastnameEmptyError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
{{input id="newUserEmail" type="text" value=newUser.email class=(if hasEmailEmptyError 'error')}}
|
||||
</div>
|
||||
<div class="regular-button button-blue" {{ action 'add' }}>Add</div>
|
||||
</form>
|
|
@ -15,4 +15,16 @@ export default {
|
|||
Private: 2,
|
||||
Protected: 3
|
||||
},
|
||||
|
||||
AuthProvider: {
|
||||
Documize: 'documize',
|
||||
Keycloak: 'keycloak'
|
||||
},
|
||||
|
||||
DocumentActionType: {
|
||||
Read: 1,
|
||||
Feedback: 2,
|
||||
Contribute: 3,
|
||||
Approve: 4
|
||||
}
|
||||
};
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
//
|
||||
// https://documize.com
|
||||
|
||||
// make url friendly slug from specified text.
|
||||
// Make url friendly slug from specified text.
|
||||
// Has to handle non-english character text "Общее" text!
|
||||
function makeSlug(text) {
|
||||
return text.toLowerCase().replace(/[^\w ]+/g, '').replace(/ +/g, '-');
|
||||
return slug(text, { mode: 'rfc3986', lower: true});
|
||||
//return text.toLowerCase().replace(/[^\w ]+/g, '').replace(/ +/g, '-');
|
||||
}
|
||||
|
||||
function makeId(len) {
|
||||
|
@ -33,4 +35,5 @@ export default {
|
|||
makeSlug,
|
||||
makeId,
|
||||
endsWith
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -60,6 +60,8 @@ module.exports = function (defaults) {
|
|||
app.import('vendor/waypoints.js');
|
||||
app.import('vendor/velocity.js');
|
||||
app.import('vendor/velocity.ui.js');
|
||||
app.import('vendor/keycloak.js');
|
||||
app.import('vendor/slug.js');
|
||||
|
||||
return app.toTree();
|
||||
};
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"node": true,
|
||||
"browser": false
|
||||
}
|
|
@ -31,11 +31,11 @@ export default function () {
|
|||
this.get('/documents', function (schema, request) {
|
||||
let folder_id = request.queryParams.folder;
|
||||
|
||||
if (folder_id = "VzMuyEw_3WqiafcG") {
|
||||
if (folder_id === "VzMuyEw_3WqiafcG") {
|
||||
return schema.db.documents.where({ folderId: folder_id });
|
||||
}
|
||||
|
||||
if (folder_id = 'V0Vy5Uw_3QeDAMW9') {
|
||||
if (folder_id === 'V0Vy5Uw_3QeDAMW9') {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -16,34 +16,33 @@
|
|||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
},
|
||||
"author": "",
|
||||
"author": "Documize Inc.",
|
||||
"license": "AGPL",
|
||||
"devDependencies": {
|
||||
"broccoli-asset-rev": "^2.4.5",
|
||||
"ember-ajax": "^2.4.1",
|
||||
"ember-cli": "2.11.1",
|
||||
"ember-cli": "2.12.0",
|
||||
"ember-cli-app-version": "^2.0.0",
|
||||
"ember-cli-babel": "^5.1.7",
|
||||
"ember-cli-dependency-checker": "^1.3.0",
|
||||
"ember-cli-eslint": "^3.0.0",
|
||||
"ember-cli-htmlbars": "^1.1.1",
|
||||
"ember-cli-htmlbars-inline-precompile": "^0.3.6",
|
||||
"ember-cli-inject-live-reload": "^1.4.1",
|
||||
"ember-cli-jshint": "^2.0.1",
|
||||
"ember-cli-mirage": "^0.2.0",
|
||||
"ember-cli-qunit": "^3.0.1",
|
||||
"ember-cli-release": "^0.2.9",
|
||||
"ember-cli-qunit": "^3.1.0",
|
||||
"ember-cli-sass": "5.3.1",
|
||||
"ember-cli-shims": "^1.0.2",
|
||||
"ember-cli-sri": "^2.1.0",
|
||||
"ember-cli-test-loader": "^1.1.0",
|
||||
"ember-cli-uglify": "^1.2.0",
|
||||
"ember-data": "^2.11.0",
|
||||
"ember-data": "^2.12.0",
|
||||
"ember-export-application-global": "^1.0.5",
|
||||
"ember-load-initializers": "^0.6.0",
|
||||
"ember-resolver": "^2.0.3",
|
||||
"ember-simple-auth": "git+https://github.com/documize/ember-simple-auth.git#21e638f9e33267d8944835002ee96884d34d568a",
|
||||
"ember-source": "~2.11.0",
|
||||
"loader.js": "^4.0.10"
|
||||
"ember-simple-auth": "1.2.0",
|
||||
"ember-source": "~2.12.0",
|
||||
"loader.js": "^4.2.3"
|
||||
},
|
||||
"ember-addon": {
|
||||
"paths": [
|
||||
|
|
|
@ -1 +1 @@
|
|||
tinymce.PluginManager.add("advlist",function(e){function t(t){return e.$.contains(e.getBody(),t)}function n(e){return e&&/^(OL|UL|DL)$/.test(e.nodeName)&&t(e)}function r(e,t){var n=[];return t&&tinymce.each(t.split(/[ ,]/),function(e){n.push({text:e.replace(/\-/g," ").replace(/\b\w/g,function(e){return e.toUpperCase()}),data:"default"==e?"":e})}),n}function i(t,n){e.undoManager.transact(function(){var r,i=e.dom,o=e.selection;if(r=i.getParent(o.getNode(),"ol,ul"),!r||r.nodeName!=t||n===!1){var a={"list-style-type":n?n:""};e.execCommand("UL"==t?"InsertUnorderedList":"InsertOrderedList",!1,a)}r=i.getParent(o.getNode(),"ol,ul"),r&&tinymce.util.Tools.each(i.select("ol,ul",r).concat([r]),function(e){e.nodeName!==t&&n!==!1&&(e=i.rename(e,t)),i.setStyle(e,"listStyleType",n?n:null),e.removeAttribute("data-mce-style")}),e.focus()})}function o(t){var n=e.dom.getStyle(e.dom.getParent(e.selection.getNode(),"ol,ul"),"listStyleType")||"";t.control.items().each(function(e){e.active(e.settings.data===n)})}var a,s,l=function(e,t){var n=e.settings.plugins?e.settings.plugins:"";return tinymce.util.Tools.inArray(n.split(/[ ,]/),t)!==-1};a=r("OL",e.getParam("advlist_number_styles","default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman")),s=r("UL",e.getParam("advlist_bullet_styles","default,circle,disc,square"));var c=function(t){return function(){var r=this;e.on("NodeChange",function(e){var i=tinymce.util.Tools.grep(e.parents,n);r.active(i.length>0&&i[0].nodeName===t)})}};l(e,"lists")&&(e.addCommand("ApplyUnorderedListStyle",function(e,t){i("UL",t["list-style-type"])}),e.addCommand("ApplyOrderedListStyle",function(e,t){i("OL",t["list-style-type"])}),e.addButton("numlist",{type:a.length>0?"splitbutton":"button",tooltip:"Numbered list",menu:a,onPostRender:c("OL"),onshow:o,onselect:function(e){i("OL",e.control.settings.data)},onclick:function(){i("OL",!1)}}),e.addButton("bullist",{type:s.length>0?"splitbutton":"button",tooltip:"Bullet list",onPostRender:c("UL"),menu:s,onshow:o,onselect:function(e){i("UL",e.control.settings.data)},onclick:function(){i("UL",!1)}}))});
|
||||
tinymce.PluginManager.add("advlist",function(e){function t(t){return e.$.contains(e.getBody(),t)}function n(e){return e&&/^(OL|UL|DL)$/.test(e.nodeName)&&t(e)}function r(e,t){var n=[];return t&&tinymce.each(t.split(/[ ,]/),function(e){n.push({text:e.replace(/\-/g," ").replace(/\b\w/g,function(e){return e.toUpperCase()}),data:"default"==e?"":e})}),n}function i(t,n){e.undoManager.transact(function(){var r,i=e.dom,o=e.selection;if(r=i.getParent(o.getNode(),"ol,ul"),!r||r.nodeName!=t||n===!1){var a={"list-style-type":n?n:""};e.execCommand("UL"==t?"InsertUnorderedList":"InsertOrderedList",!1,a)}r=i.getParent(o.getNode(),"ol,ul"),r&&tinymce.util.Tools.each(i.select("ol,ul",r).concat([r]),function(e){e.nodeName!==t&&n!==!1&&(e=i.rename(e,t)),i.setStyle(e,"listStyleType",n?n:null),e.removeAttribute("data-mce-style")}),e.focus()})}function o(t){var n=e.dom.getStyle(e.dom.getParent(e.selection.getNode(),"ol,ul"),"listStyleType")||"";t.control.items().each(function(e){e.active(e.settings.data===n)})}var a,s,l=function(e,t){var n=e.settings.plugins?e.settings.plugins:"";return tinymce.util.Tools.inArray(n.split(/[ ,]/),t)!==-1};a=r("OL",e.getParam("advlist_number_styles","default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman")),s=r("UL",e.getParam("advlist_bullet_styles","default,circle,disc,square"));var u=function(t){return function(){var r=this;e.on("NodeChange",function(e){var i=tinymce.util.Tools.grep(e.parents,n);r.active(i.length>0&&i[0].nodeName===t)})}};l(e,"lists")&&(e.addCommand("ApplyUnorderedListStyle",function(e,t){i("UL",t["list-style-type"])}),e.addCommand("ApplyOrderedListStyle",function(e,t){i("OL",t["list-style-type"])}),e.addButton("numlist",{type:a.length>0?"splitbutton":"button",tooltip:"Numbered list",menu:a,onPostRender:u("OL"),onshow:o,onselect:function(e){i("OL",e.control.settings.data)},onclick:function(){i("OL",!1)}}),e.addButton("bullist",{type:s.length>0?"splitbutton":"button",tooltip:"Bullet list",onPostRender:u("UL"),menu:s,onshow:o,onselect:function(e){i("UL",e.control.settings.data)},onclick:function(){i("UL",!1)}}))});
|
|
@ -1 +1 @@
|
|||
tinymce.PluginManager.add("anchor",function(e){var t=function(e){return!e.attr("href")&&(e.attr("id")||e.attr("name"))&&!e.firstChild},n=function(e){return function(n){for(var r=0;r<n.length;r++)t(n[r])&&n[r].attr("contenteditable",e)}},r=function(){var t=e.selection.getNode(),n="A"==t.tagName&&""===e.dom.getAttrib(t,"href"),r="";n&&(r=t.id||t.name||""),e.windowManager.open({title:"Anchor",body:{type:"textbox",name:"id",size:40,label:"Id",value:r},onsubmit:function(r){var i=r.data.id;n?(t.removeAttribute("name"),t.id=i):(e.selection.collapse(!0),e.execCommand("mceInsertContent",!1,e.dom.createHTML("a",{id:i})))}})};tinymce.Env.ceFalse&&e.on("PreInit",function(){e.parser.addNodeFilter("a",n("false")),e.serializer.addNodeFilter("a",n(null))}),e.addCommand("mceAnchor",r),e.addButton("anchor",{icon:"anchor",tooltip:"Anchor",onclick:r,stateSelector:"a:not([href])"}),e.addMenuItem("anchor",{icon:"anchor",text:"Anchor",context:"insert",onclick:r})});
|
||||
tinymce.PluginManager.add("anchor",function(e){var t=function(e){return!e.attr("href")&&(e.attr("id")||e.attr("name"))&&!e.firstChild},n=function(e){return function(n){for(var r=0;r<n.length;r++)t(n[r])&&n[r].attr("contenteditable",e)}},r=function(e){return/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(e)},i=function(){var t=e.selection.getNode(),n="A"==t.tagName&&""===e.dom.getAttrib(t,"href"),i="";n&&(i=t.id||t.name||""),e.windowManager.open({title:"Anchor",body:{type:"textbox",name:"id",size:40,label:"Id",value:i},onsubmit:function(i){var o=i.data.id;return r(o)?void(n?(t.removeAttribute("name"),t.id=o):(e.selection.collapse(!0),e.execCommand("mceInsertContent",!1,e.dom.createHTML("a",{id:o})))):(i.preventDefault(),void e.windowManager.alert("Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."))}})};tinymce.Env.ceFalse&&e.on("PreInit",function(){e.parser.addNodeFilter("a",n("false")),e.serializer.addNodeFilter("a",n(null))}),e.addCommand("mceAnchor",i),e.addButton("anchor",{icon:"anchor",tooltip:"Anchor",onclick:i,stateSelector:"a:not([href])"}),e.addMenuItem("anchor",{icon:"anchor",text:"Anchor",context:"insert",onclick:i})});
|
|
@ -1 +1 @@
|
|||
tinymce.PluginManager.add("autolink",function(e){function t(e){i(e,-1,"(",!0)}function n(e){i(e,0,"",!0)}function r(e){i(e,-1,"",!1)}function i(e,t,n){function r(e,t){if(t<0&&(t=0),3==e.nodeType){var n=e.data.length;t>n&&(t=n)}return t}function i(e,t){1!=e.nodeType||e.hasChildNodes()?s.setStart(e,r(e,t)):s.setStartBefore(e)}function o(e,t){1!=e.nodeType||e.hasChildNodes()?s.setEnd(e,r(e,t)):s.setEndAfter(e)}var s,l,c,u,d,f,p,m,g,h;if("A"!=e.selection.getNode().tagName){if(s=e.selection.getRng(!0).cloneRange(),s.startOffset<5){if(m=s.endContainer.previousSibling,!m){if(!s.endContainer.firstChild||!s.endContainer.firstChild.nextSibling)return;m=s.endContainer.firstChild.nextSibling}if(g=m.length,i(m,g),o(m,g),s.endOffset<5)return;l=s.endOffset,u=m}else{if(u=s.endContainer,3!=u.nodeType&&u.firstChild){for(;3!=u.nodeType&&u.firstChild;)u=u.firstChild;3==u.nodeType&&(i(u,0),o(u,u.nodeValue.length))}l=1==s.endOffset?2:s.endOffset-1-t}c=l;do i(u,l>=2?l-2:0),o(u,l>=1?l-1:0),l-=1,h=s.toString();while(" "!=h&&""!==h&&160!=h.charCodeAt(0)&&l-2>=0&&h!=n);s.toString()==n||160==s.toString().charCodeAt(0)?(i(u,l),o(u,c),l+=1):0===s.startOffset?(i(u,0),o(u,c)):(i(u,l),o(u,c)),f=s.toString(),"."==f.charAt(f.length-1)&&o(u,c-1),f=s.toString(),p=f.match(a),p&&("www."==p[1]?p[1]="http://www.":/@$/.test(p[1])&&!/^mailto:/.test(p[1])&&(p[1]="mailto:"+p[1]),d=e.selection.getBookmark(),e.selection.setRng(s),e.execCommand("createlink",!1,p[1]+p[2]),e.settings.default_link_target&&e.dom.setAttrib(e.selection.getNode(),"target",e.settings.default_link_target),e.selection.moveToBookmark(d),e.nodeChanged())}}var o,a=/^(https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.|(?:mailto:)?[A-Z0-9._%+\-]+@)(.+)$/i;return e.settings.autolink_pattern&&(a=e.settings.autolink_pattern),e.on("keydown",function(t){if(13==t.keyCode)return r(e)}),tinymce.Env.ie?void e.on("focus",function(){if(!o){o=!0;try{e.execCommand("AutoUrlDetect",!1,!0)}catch(e){}}}):(e.on("keypress",function(n){if(41==n.keyCode)return t(e)}),void e.on("keyup",function(t){if(32==t.keyCode)return n(e)}))});
|
||||
tinymce.PluginManager.add("autolink",function(e){function t(e){i(e,-1,"(",!0)}function n(e){i(e,0,"",!0)}function r(e){i(e,-1,"",!1)}function i(e,t,n){function r(e,t){if(t<0&&(t=0),3==e.nodeType){var n=e.data.length;t>n&&(t=n)}return t}function i(e,t){1!=e.nodeType||e.hasChildNodes()?s.setStart(e,r(e,t)):s.setStartBefore(e)}function o(e,t){1!=e.nodeType||e.hasChildNodes()?s.setEnd(e,r(e,t)):s.setEndAfter(e)}var s,l,u,c,d,f,p,h,m,g;if("A"!=e.selection.getNode().tagName){if(s=e.selection.getRng(!0).cloneRange(),s.startOffset<5){if(h=s.endContainer.previousSibling,!h){if(!s.endContainer.firstChild||!s.endContainer.firstChild.nextSibling)return;h=s.endContainer.firstChild.nextSibling}if(m=h.length,i(h,m),o(h,m),s.endOffset<5)return;l=s.endOffset,c=h}else{if(c=s.endContainer,3!=c.nodeType&&c.firstChild){for(;3!=c.nodeType&&c.firstChild;)c=c.firstChild;3==c.nodeType&&(i(c,0),o(c,c.nodeValue.length))}l=1==s.endOffset?2:s.endOffset-1-t}u=l;do i(c,l>=2?l-2:0),o(c,l>=1?l-1:0),l-=1,g=s.toString();while(" "!=g&&""!==g&&160!=g.charCodeAt(0)&&l-2>=0&&g!=n);s.toString()==n||160==s.toString().charCodeAt(0)?(i(c,l),o(c,u),l+=1):0===s.startOffset?(i(c,0),o(c,u)):(i(c,l),o(c,u)),f=s.toString(),"."==f.charAt(f.length-1)&&o(c,u-1),f=s.toString(),p=f.match(a),p&&("www."==p[1]?p[1]="http://www.":/@$/.test(p[1])&&!/^mailto:/.test(p[1])&&(p[1]="mailto:"+p[1]),d=e.selection.getBookmark(),e.selection.setRng(s),e.execCommand("createlink",!1,p[1]+p[2]),e.settings.default_link_target&&e.dom.setAttrib(e.selection.getNode(),"target",e.settings.default_link_target),e.selection.moveToBookmark(d),e.nodeChanged())}}var o,a=/^(https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.|(?:mailto:)?[A-Z0-9._%+\-]+@)(.+)$/i;return e.settings.autolink_pattern&&(a=e.settings.autolink_pattern),e.on("keydown",function(t){if(13==t.keyCode)return r(e)}),tinymce.Env.ie?void e.on("focus",function(){if(!o){o=!0;try{e.execCommand("AutoUrlDetect",!1,!0)}catch(e){}}}):(e.on("keypress",function(n){if(41==n.keyCode)return t(e)}),void e.on("keyup",function(t){if(32==t.keyCode)return n(e)}))});
|
|
@ -1 +1 @@
|
|||
tinymce.PluginManager.add("autoresize",function(e){function t(){return e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen()}function n(r){var a,s,l,c,u,d,f,p,m,g,h,v,b=tinymce.DOM;if(s=e.getDoc()){if(l=s.body,c=s.documentElement,u=i.autoresize_min_height,!l||r&&"setcontent"===r.type&&r.initial||t())return void(l&&c&&(l.style.overflowY="auto",c.style.overflowY="auto"));f=e.dom.getStyle(l,"margin-top",!0),p=e.dom.getStyle(l,"margin-bottom",!0),m=e.dom.getStyle(l,"padding-top",!0),g=e.dom.getStyle(l,"padding-bottom",!0),h=e.dom.getStyle(l,"border-top-width",!0),v=e.dom.getStyle(l,"border-bottom-width",!0),d=l.offsetHeight+parseInt(f,10)+parseInt(p,10)+parseInt(m,10)+parseInt(g,10)+parseInt(h,10)+parseInt(v,10),(isNaN(d)||d<=0)&&(d=tinymce.Env.ie?l.scrollHeight:tinymce.Env.webkit&&0===l.clientHeight?0:l.offsetHeight),d>i.autoresize_min_height&&(u=d),i.autoresize_max_height&&d>i.autoresize_max_height?(u=i.autoresize_max_height,l.style.overflowY="auto",c.style.overflowY="auto"):(l.style.overflowY="hidden",c.style.overflowY="hidden",l.scrollTop=0),u!==o&&(a=u-o,b.setStyle(e.iframeElement,"height",u+"px"),o=u,tinymce.isWebKit&&a<0&&n(r))}}function r(t,i,o){tinymce.util.Delay.setEditorTimeout(e,function(){n({}),t--?r(t,i,o):o&&o()},i)}var i=e.settings,o=0;e.settings.inline||(i.autoresize_min_height=parseInt(e.getParam("autoresize_min_height",e.getElement().offsetHeight),10),i.autoresize_max_height=parseInt(e.getParam("autoresize_max_height",0),10),e.on("init",function(){var t,n;t=e.getParam("autoresize_overflow_padding",1),n=e.getParam("autoresize_bottom_margin",50),t!==!1&&e.dom.setStyles(e.getBody(),{paddingLeft:t,paddingRight:t}),n!==!1&&e.dom.setStyles(e.getBody(),{paddingBottom:n})}),e.on("nodechange setcontent keyup FullscreenStateChanged",n),e.getParam("autoresize_on_init",!0)&&e.on("init",function(){r(20,100,function(){r(5,1e3)})}),e.addCommand("mceAutoResize",n))});
|
||||
tinymce.PluginManager.add("autoresize",function(e){function t(){return e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen()}function n(r){var a,s,l,u,c,d,f,p,h,m,g,v,y=tinymce.DOM;if(s=e.getDoc()){if(l=s.body,u=s.documentElement,c=i.autoresize_min_height,!l||r&&"setcontent"===r.type&&r.initial||t())return void(l&&u&&(l.style.overflowY="auto",u.style.overflowY="auto"));f=e.dom.getStyle(l,"margin-top",!0),p=e.dom.getStyle(l,"margin-bottom",!0),h=e.dom.getStyle(l,"padding-top",!0),m=e.dom.getStyle(l,"padding-bottom",!0),g=e.dom.getStyle(l,"border-top-width",!0),v=e.dom.getStyle(l,"border-bottom-width",!0),d=l.offsetHeight+parseInt(f,10)+parseInt(p,10)+parseInt(h,10)+parseInt(m,10)+parseInt(g,10)+parseInt(v,10),(isNaN(d)||d<=0)&&(d=tinymce.Env.ie?l.scrollHeight:tinymce.Env.webkit&&0===l.clientHeight?0:l.offsetHeight),d>i.autoresize_min_height&&(c=d),i.autoresize_max_height&&d>i.autoresize_max_height?(c=i.autoresize_max_height,l.style.overflowY="auto",u.style.overflowY="auto"):(l.style.overflowY="hidden",u.style.overflowY="hidden",l.scrollTop=0),c!==o&&(a=c-o,y.setStyle(e.iframeElement,"height",c+"px"),o=c,tinymce.isWebKit&&a<0&&n(r))}}function r(t,i,o){tinymce.util.Delay.setEditorTimeout(e,function(){n({}),t--?r(t,i,o):o&&o()},i)}var i=e.settings,o=0;e.settings.inline||(i.autoresize_min_height=parseInt(e.getParam("autoresize_min_height",e.getElement().offsetHeight),10),i.autoresize_max_height=parseInt(e.getParam("autoresize_max_height",0),10),e.on("init",function(){var t,n;t=e.getParam("autoresize_overflow_padding",1),n=e.getParam("autoresize_bottom_margin",50),t!==!1&&e.dom.setStyles(e.getBody(),{paddingLeft:t,paddingRight:t}),n!==!1&&e.dom.setStyles(e.getBody(),{paddingBottom:n})}),e.on("nodechange setcontent keyup FullscreenStateChanged",n),e.getParam("autoresize_on_init",!0)&&e.on("init",function(){r(20,100,function(){r(5,1e3)})}),e.addCommand("mceAutoResize",n))});
|
|
@ -1 +1 @@
|
|||
tinymce._beforeUnloadHandler=function(){var e;return tinymce.each(tinymce.editors,function(t){t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&t.getParam("autosave_ask_before_unload",!0)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))}),e},tinymce.PluginManager.add("autosave",function(e){function t(e,t){var n={s:1e3,m:6e4};return e=/^(\d+)([ms]?)$/.exec(""+(e||t)),(e[2]?n[e[2]]:1)*parseInt(e,10)}function n(){var e=parseInt(p.getItem(u+"time"),10)||0;return!((new Date).getTime()-e>f.autosave_retention)||(r(!1),!1)}function r(t){p.removeItem(u+"draft"),p.removeItem(u+"time"),t!==!1&&e.fire("RemoveDraft")}function i(){!c()&&e.isDirty()&&(p.setItem(u+"draft",e.getContent({format:"raw",no_events:!0})),p.setItem(u+"time",(new Date).getTime()),e.fire("StoreDraft"))}function o(){n()&&(e.setContent(p.getItem(u+"draft"),{format:"raw"}),e.fire("RestoreDraft"))}function a(){d||(setInterval(function(){e.removed||i()},f.autosave_interval),d=!0)}function s(){var t=this;t.disabled(!n()),e.on("StoreDraft RestoreDraft RemoveDraft",function(){t.disabled(!n())}),a()}function l(){e.undoManager.beforeChange(),o(),r(),e.undoManager.add()}function c(t){var n=e.settings.forced_root_block;return t=tinymce.trim("undefined"==typeof t?e.getBody().innerHTML:t),""===t||new RegExp("^<"+n+"[^>]*>((\xa0| |[ \t]|<br[^>]*>)+?|)</"+n+">|<br>$","i").test(t)}var u,d,f=e.settings,p=tinymce.util.LocalStorage;u=f.autosave_prefix||"tinymce-autosave-{path}{query}-{id}-",u=u.replace(/\{path\}/g,document.location.pathname),u=u.replace(/\{query\}/g,document.location.search),u=u.replace(/\{id\}/g,e.id),f.autosave_interval=t(f.autosave_interval,"30s"),f.autosave_retention=t(f.autosave_retention,"20m"),e.addButton("restoredraft",{title:"Restore last draft",onclick:l,onPostRender:s}),e.addMenuItem("restoredraft",{text:"Restore last draft",onclick:l,onPostRender:s,context:"file"}),e.settings.autosave_restore_when_empty!==!1&&(e.on("init",function(){n()&&c()&&o()}),e.on("saveContent",function(){r()})),window.onbeforeunload=tinymce._beforeUnloadHandler,this.hasDraft=n,this.storeDraft=i,this.restoreDraft=o,this.removeDraft=r,this.isEmpty=c});
|
||||
tinymce._beforeUnloadHandler=function(){var e;return tinymce.each(tinymce.editors,function(t){t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&t.getParam("autosave_ask_before_unload",!0)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))}),e},tinymce.PluginManager.add("autosave",function(e){function t(e,t){var n={s:1e3,m:6e4};return e=/^(\d+)([ms]?)$/.exec(""+(e||t)),(e[2]?n[e[2]]:1)*parseInt(e,10)}function n(){var e=parseInt(p.getItem(c+"time"),10)||0;return!((new Date).getTime()-e>f.autosave_retention)||(r(!1),!1)}function r(t){p.removeItem(c+"draft"),p.removeItem(c+"time"),t!==!1&&e.fire("RemoveDraft")}function i(){!u()&&e.isDirty()&&(p.setItem(c+"draft",e.getContent({format:"raw",no_events:!0})),p.setItem(c+"time",(new Date).getTime()),e.fire("StoreDraft"))}function o(){n()&&(e.setContent(p.getItem(c+"draft"),{format:"raw"}),e.fire("RestoreDraft"))}function a(){d||(setInterval(function(){e.removed||i()},f.autosave_interval),d=!0)}function s(){var t=this;t.disabled(!n()),e.on("StoreDraft RestoreDraft RemoveDraft",function(){t.disabled(!n())}),a()}function l(){e.undoManager.beforeChange(),o(),r(),e.undoManager.add()}function u(t){var n=e.settings.forced_root_block;return t=tinymce.trim("undefined"==typeof t?e.getBody().innerHTML:t),""===t||new RegExp("^<"+n+"[^>]*>((\xa0| |[ \t]|<br[^>]*>)+?|)</"+n+">|<br>$","i").test(t)}var c,d,f=e.settings,p=tinymce.util.LocalStorage;c=f.autosave_prefix||"tinymce-autosave-{path}{query}-{id}-",c=c.replace(/\{path\}/g,document.location.pathname),c=c.replace(/\{query\}/g,document.location.search),c=c.replace(/\{id\}/g,e.id),f.autosave_interval=t(f.autosave_interval,"30s"),f.autosave_retention=t(f.autosave_retention,"20m"),e.addButton("restoredraft",{title:"Restore last draft",onclick:l,onPostRender:s}),e.addMenuItem("restoredraft",{text:"Restore last draft",onclick:l,onPostRender:s,context:"file"}),e.settings.autosave_restore_when_empty!==!1&&(e.on("init",function(){n()&&u()&&o()}),e.on("saveContent",function(){r()})),window.onbeforeunload=tinymce._beforeUnloadHandler,this.hasDraft=n,this.storeDraft=i,this.restoreDraft=o,this.removeDraft=r,this.isEmpty=u});
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue