mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-08-25 03:35:35 +00:00
Merge branch 'master' into bug/image-upload
This commit is contained in:
commit
0335f58478
@ -120,7 +120,7 @@ class ImageController extends Controller
|
||||
{
|
||||
$this->checkPermission('image-create-all');
|
||||
$this->validate($request, [
|
||||
'file' => 'image'
|
||||
'file' => 'required|image'
|
||||
]);
|
||||
|
||||
if (!$this->imageRepo->isValidType($type)) {
|
||||
|
@ -713,6 +713,10 @@ class EntityRepo
|
||||
public function renderPage(Page $page, $ignorePermissions = false)
|
||||
{
|
||||
$content = $page->html;
|
||||
if (!config('app.allow_content_scripts')) {
|
||||
$content = $this->escapeScripts($content);
|
||||
}
|
||||
|
||||
$matches = [];
|
||||
preg_match_all("/{{@\s?([0-9].*?)}}/", $content, $matches);
|
||||
if (count($matches[0]) === 0) {
|
||||
@ -760,6 +764,24 @@ class EntityRepo
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape script tags within HTML content.
|
||||
* @param string $html
|
||||
* @return mixed
|
||||
*/
|
||||
protected function escapeScripts(string $html)
|
||||
{
|
||||
$scriptSearchRegex = '/<script.*?>.*?<\/script>/ms';
|
||||
$matches = [];
|
||||
preg_match_all($scriptSearchRegex, $html, $matches);
|
||||
if (count($matches) === 0) return $html;
|
||||
|
||||
foreach ($matches[0] as $match) {
|
||||
$html = str_replace($match, htmlentities($match), $html);
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plain text version of a page's content.
|
||||
* @param Page $page
|
||||
|
@ -8,6 +8,8 @@ return [
|
||||
'books' => env('APP_VIEWS_BOOKS', 'list')
|
||||
],
|
||||
|
||||
'allow_content_scripts' => env('ALLOW_CONTENT_SCRIPTS', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Debug Mode
|
||||
@ -148,8 +150,6 @@ return [
|
||||
*/
|
||||
Intervention\Image\ImageServiceProvider::class,
|
||||
Barryvdh\DomPDF\ServiceProvider::class,
|
||||
Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
|
||||
Barryvdh\Debugbar\ServiceProvider::class,
|
||||
Barryvdh\Snappy\ServiceProvider::class,
|
||||
|
||||
|
||||
@ -164,7 +164,6 @@ return [
|
||||
BookStack\Providers\EventServiceProvider::class,
|
||||
BookStack\Providers\RouteServiceProvider::class,
|
||||
BookStack\Providers\CustomFacadeProvider::class,
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
@ -222,7 +221,6 @@ return [
|
||||
'ImageTool' => Intervention\Image\Facades\Image::class,
|
||||
'DomPDF' => Barryvdh\DomPDF\Facade::class,
|
||||
'SnappyPDF' => Barryvdh\Snappy\Facades\SnappyPdf::class,
|
||||
'Debugbar' => Barryvdh\Debugbar\Facade::class,
|
||||
|
||||
/**
|
||||
* Custom
|
||||
|
83
gulpfile.js
83
gulpfile.js
@ -1,83 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const argv = require('yargs').argv;
|
||||
const gulp = require('gulp'),
|
||||
plumber = require('gulp-plumber');
|
||||
|
||||
const autoprefixer = require('gulp-autoprefixer');
|
||||
const minifycss = require('gulp-clean-css');
|
||||
const sass = require('gulp-sass');
|
||||
const sourcemaps = require('gulp-sourcemaps');
|
||||
|
||||
const browserify = require("browserify");
|
||||
const source = require('vinyl-source-stream');
|
||||
const buffer = require('vinyl-buffer');
|
||||
const babelify = require("babelify");
|
||||
const watchify = require("watchify");
|
||||
const envify = require("envify");
|
||||
const uglify = require('gulp-uglify');
|
||||
|
||||
const gutil = require("gulp-util");
|
||||
const liveReload = require('gulp-livereload');
|
||||
|
||||
if (argv.production) process.env.NODE_ENV = 'production';
|
||||
let isProduction = argv.production || process.env.NODE_ENV === 'production';
|
||||
|
||||
gulp.task('styles', () => {
|
||||
let chain = gulp.src(['resources/assets/sass/**/*.scss'])
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(plumber({
|
||||
errorHandler: function (error) {
|
||||
console.log(error.message);
|
||||
this.emit('end');
|
||||
}}))
|
||||
.pipe(sass())
|
||||
.pipe(autoprefixer('last 2 versions'));
|
||||
if (isProduction) chain = chain.pipe(minifycss());
|
||||
chain = chain.pipe(sourcemaps.write());
|
||||
return chain.pipe(gulp.dest('public/css/')).pipe(liveReload());
|
||||
});
|
||||
|
||||
|
||||
function scriptTask(watch = false) {
|
||||
|
||||
let props = {
|
||||
basedir: 'resources/assets/js',
|
||||
debug: true,
|
||||
entries: ['global.js'],
|
||||
fast: !isProduction,
|
||||
cache: {},
|
||||
packageCache: {},
|
||||
};
|
||||
|
||||
let bundler = watch ? watchify(browserify(props), { poll: true }) : browserify(props);
|
||||
|
||||
if (isProduction) {
|
||||
bundler.transform(envify, {global: true}).transform(babelify, {presets: ['es2015']});
|
||||
}
|
||||
|
||||
function rebundle() {
|
||||
let stream = bundler.bundle();
|
||||
stream = stream.pipe(source('common.js'));
|
||||
if (isProduction) stream = stream.pipe(buffer()).pipe(uglify());
|
||||
return stream.pipe(gulp.dest('public/js/')).pipe(liveReload());
|
||||
}
|
||||
|
||||
bundler.on('update', function() {
|
||||
rebundle();
|
||||
gutil.log('Rebundling assets...');
|
||||
});
|
||||
|
||||
bundler.on('log', gutil.log);
|
||||
return rebundle();
|
||||
}
|
||||
|
||||
gulp.task('scripts', () => {scriptTask(false)});
|
||||
gulp.task('scripts-watch', () => {scriptTask(true)});
|
||||
|
||||
gulp.task('default', ['styles', 'scripts-watch'], () => {
|
||||
liveReload.listen();
|
||||
gulp.watch("resources/assets/sass/**/*.scss", ['styles']);
|
||||
});
|
||||
|
||||
gulp.task('build', ['styles', 'scripts']);
|
10556
package-lock.json
generated
10556
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
53
package.json
53
package.json
@ -1,41 +1,40 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "gulp build",
|
||||
"production": "gulp build --production",
|
||||
"dev": "gulp",
|
||||
"watch": "gulp",
|
||||
"build": "webpack",
|
||||
"production": "NODE_ENV=production webpack && rm -f ./public/dist/*styles.js",
|
||||
"dev": "npm-run-all --parallel watch livereload",
|
||||
"watch": "webpack --watch",
|
||||
"livereload": "livereload ./public/dist/",
|
||||
"permissions": "chown -R $USER:$USER bootstrap/cache storage public/uploads"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babelify": "^7.3.0",
|
||||
"browserify": "^14.3.0",
|
||||
"envify": "^4.0.0",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-autoprefixer": "3.1.1",
|
||||
"gulp-clean-css": "^3.0.4",
|
||||
"gulp-livereload": "^3.8.1",
|
||||
"gulp-minify-css": "1.2.4",
|
||||
"gulp-plumber": "1.1.0",
|
||||
"gulp-sass": "3.1.0",
|
||||
"gulp-uglify": "2.1.2",
|
||||
"vinyl-buffer": "^1.0.0",
|
||||
"vinyl-source-stream": "^1.1.0",
|
||||
"watchify": "^3.9.0",
|
||||
"yargs": "^7.1.0"
|
||||
"@babel/core": "^7.0.0-beta.40",
|
||||
"@babel/preset-env": "^7.0.0-beta.40",
|
||||
"autoprefixer": "^8.1.0",
|
||||
"babel-loader": "^8.0.0-beta.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"css-loader": "^0.28.10",
|
||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||
"livereload": "^0.7.0",
|
||||
"node-sass": "^4.7.2",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"postcss-loader": "^2.1.1",
|
||||
"sass-loader": "^6.0.7",
|
||||
"style-loader": "^0.20.3",
|
||||
"uglifyjs-webpack-plugin": "^1.2.3",
|
||||
"webpack": "^4.1.1",
|
||||
"webpack-cli": "^2.0.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.16.1",
|
||||
"babel-polyfill": "^6.23.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"clipboard": "^1.7.1",
|
||||
"axios": "^0.18.0",
|
||||
"clipboard": "^2.0.0",
|
||||
"codemirror": "^5.26.0",
|
||||
"dropzone": "^4.0.1",
|
||||
"gulp-sourcemaps": "^2.6.1",
|
||||
"gulp-util": "^3.0.8",
|
||||
"dropzone": "^5.4.0",
|
||||
"jquery": "^3.3.1",
|
||||
"markdown-it": "^8.3.1",
|
||||
"markdown-it-task-lists": "^2.0.0",
|
||||
"moment": "^2.12.0",
|
||||
"moment": "^2.21.0",
|
||||
"vue": "^2.2.6",
|
||||
"vuedraggable": "^2.14.1"
|
||||
},
|
||||
|
7
public/libs/jquery/jquery-ui.min.js
vendored
7
public/libs/jquery/jquery-ui.min.js
vendored
File diff suppressed because one or more lines are too long
5
public/libs/jquery/jquery.min.js
vendored
5
public/libs/jquery/jquery.min.js
vendored
File diff suppressed because one or more lines are too long
@ -16,12 +16,12 @@ let componentMapping = {
|
||||
'editor-toolbox': require('./editor-toolbox'),
|
||||
'image-picker': require('./image-picker'),
|
||||
'collapsible': require('./collapsible'),
|
||||
'toggle-switch': require('./toggle-switch'),
|
||||
};
|
||||
|
||||
window.components = {};
|
||||
|
||||
let componentNames = Object.keys(componentMapping);
|
||||
initAll();
|
||||
|
||||
/**
|
||||
* Initialize components of the given name within the given element.
|
||||
@ -53,4 +53,6 @@ function initAll(parentElement) {
|
||||
}
|
||||
}
|
||||
|
||||
window.components.init = initAll;
|
||||
window.components.init = initAll;
|
||||
|
||||
export default initAll;
|
@ -255,7 +255,9 @@ class MarkdownEditor {
|
||||
let placeholderImage = window.baseUrl(`/loading.gif#upload${id}`);
|
||||
let selectedText = cm.getSelection();
|
||||
let placeHolderText = `![${selectedText}](${placeholderImage})`;
|
||||
let cursor = cm.getCursor();
|
||||
cm.replaceSelection(placeHolderText);
|
||||
cm.setCursor({line: cursor.line, ch: cursor.ch + selectedText.length + 2});
|
||||
|
||||
let remoteFilename = "image-" + Date.now() + "." + ext;
|
||||
let formData = new FormData();
|
||||
@ -264,7 +266,7 @@ class MarkdownEditor {
|
||||
window.$http.post('/images/gallery/upload', formData).then(resp => {
|
||||
replaceContent(placeholderImage, resp.data.thumbs.display);
|
||||
}).catch(err => {
|
||||
events.emit('error', trans('errors.image_upload_error'));
|
||||
window.$events.emit('error', trans('errors.image_upload_error'));
|
||||
replaceContent(placeHolderText, selectedText);
|
||||
console.log(err);
|
||||
});
|
||||
|
@ -18,7 +18,7 @@ class Notification {
|
||||
show(textToShow = '') {
|
||||
this.elem.removeEventListener('transitionend', this.hideCleanup);
|
||||
this.textElem.textContent = textToShow;
|
||||
this.elem.style.display = 'block';
|
||||
this.elem.style.display = 'grid';
|
||||
setTimeout(() => {
|
||||
this.elem.classList.add('showing');
|
||||
}, 1);
|
||||
|
19
resources/assets/js/components/toggle-switch.js
Normal file
19
resources/assets/js/components/toggle-switch.js
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
class ToggleSwitch {
|
||||
|
||||
constructor(elem) {
|
||||
this.elem = elem;
|
||||
this.input = elem.querySelector('input');
|
||||
|
||||
this.elem.onclick = this.onClick.bind(this);
|
||||
}
|
||||
|
||||
onClick(event) {
|
||||
let checked = this.input.value !== 'true';
|
||||
this.input.value = checked ? 'true' : 'false';
|
||||
checked ? this.elem.classList.add('active') : this.elem.classList.remove('active');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ToggleSwitch;
|
@ -1,6 +1,16 @@
|
||||
"use strict";
|
||||
require("babel-polyfill");
|
||||
require('./dom-polyfills');
|
||||
import "babel-polyfill"
|
||||
import "./dom-polyfills"
|
||||
|
||||
import jQuery from "jquery"
|
||||
window.jQuery = window.$ = jQuery;
|
||||
|
||||
import "./pages/page-show"
|
||||
import Translations from "./translations"
|
||||
import vues from "./vues/vues"
|
||||
import components from "./components"
|
||||
|
||||
import Vue from "vue"
|
||||
import axios from "axios"
|
||||
|
||||
// Url retrieval function
|
||||
window.baseUrl = function(path) {
|
||||
@ -37,9 +47,6 @@ class EventManager {
|
||||
|
||||
window.$events = new EventManager();
|
||||
|
||||
const Vue = require("vue");
|
||||
const axios = require("axios");
|
||||
|
||||
let axiosInstance = axios.create({
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name=token]').getAttribute('content'),
|
||||
@ -60,14 +67,13 @@ Vue.prototype.$events = window.$events;
|
||||
|
||||
// Translation setup
|
||||
// Creates a global function with name 'trans' to be used in the same way as Laravel's translation system
|
||||
const Translations = require("./translations");
|
||||
let translator = new Translations(window.translations);
|
||||
window.trans = translator.get.bind(translator);
|
||||
window.trans_choice = translator.getPlural.bind(translator);
|
||||
|
||||
|
||||
require("./vues/vues");
|
||||
require("./components");
|
||||
// Load vues and components
|
||||
vues();
|
||||
components();
|
||||
|
||||
|
||||
//Global jQuery Config & Extensions
|
||||
@ -125,6 +131,3 @@ if(navigator.userAgent.indexOf('MSIE')!==-1
|
||||
|| navigator.userAgent.indexOf('Safari') !== -1){
|
||||
document.body.classList.add('flexbox-support');
|
||||
}
|
||||
|
||||
// Page specific items
|
||||
require("./pages/page-show");
|
@ -350,7 +350,7 @@ if (document.querySelector('[drawio-enabled]').getAttribute('drawio-enabled') ==
|
||||
module.exports = {
|
||||
selector: '#html-editor',
|
||||
content_css: [
|
||||
window.baseUrl('/css/styles.css'),
|
||||
window.baseUrl('/dist/styles.css'),
|
||||
],
|
||||
branding: false,
|
||||
body_class: 'page-content',
|
||||
|
@ -16,10 +16,17 @@ let vueMapping = {
|
||||
|
||||
window.vues = {};
|
||||
|
||||
let ids = Object.keys(vueMapping);
|
||||
for (let i = 0, len = ids.length; i < len; i++) {
|
||||
if (!exists(ids[i])) continue;
|
||||
let config = vueMapping[ids[i]];
|
||||
config.el = '#' + ids[i];
|
||||
window.vues[ids[i]] = new Vue(config);
|
||||
}
|
||||
function load() {
|
||||
let ids = Object.keys(vueMapping);
|
||||
for (let i = 0, len = ids.length; i < len; i++) {
|
||||
if (!exists(ids[i])) continue;
|
||||
let config = vueMapping[ids[i]];
|
||||
config.el = '#' + ids[i];
|
||||
window.vues[ids[i]] = new Vue(config);
|
||||
}
|
||||
}
|
||||
|
||||
export default load;
|
||||
|
||||
|
||||
|
||||
|
@ -65,6 +65,7 @@ $button-border-radius: 2px;
|
||||
.button.outline {
|
||||
background-color: transparent;
|
||||
color: #888;
|
||||
fill: #888;
|
||||
border: 1px solid #DDD;
|
||||
&:hover, &:focus, &:active {
|
||||
box-shadow: none;
|
||||
@ -73,25 +74,31 @@ $button-border-radius: 2px;
|
||||
&.page {
|
||||
border-color: $color-page;
|
||||
color: $color-page;
|
||||
fill: $color-page;
|
||||
&:hover, &:focus, &:active {
|
||||
background-color: $color-page;
|
||||
color: #FFF;
|
||||
fill: #FFF;
|
||||
}
|
||||
}
|
||||
&.chapter {
|
||||
border-color: $color-chapter;
|
||||
color: $color-chapter;
|
||||
fill: $color-chapter;
|
||||
&:hover, &:focus, &:active {
|
||||
background-color: $color-chapter;
|
||||
color: #FFF;
|
||||
fill: #FFF;
|
||||
}
|
||||
}
|
||||
&.book {
|
||||
border-color: $color-book;
|
||||
color: $color-book;
|
||||
fill: $color-book;
|
||||
&:hover, &:focus, &:active {
|
||||
background-color: $color-book;
|
||||
color: #FFF;
|
||||
fill: #FFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,8 @@
|
||||
box-shadow: $bs-med;
|
||||
z-index: 999999;
|
||||
cursor: pointer;
|
||||
max-width: 480px;
|
||||
transition: transform ease-in-out 360ms;
|
||||
max-width: 360px;
|
||||
transition: transform ease-in-out 280ms;
|
||||
transform: translate3d(580px, 0, 0);
|
||||
display: grid;
|
||||
grid-template-columns: 64px 1fr;
|
||||
@ -27,6 +27,7 @@
|
||||
}
|
||||
span {
|
||||
vertical-align: middle;
|
||||
line-height: 1.3;
|
||||
}
|
||||
&.pos {
|
||||
background-color: $positive;
|
||||
@ -43,6 +44,9 @@
|
||||
&.showing {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
&.showing:hover {
|
||||
transform: translate3d(0, -2px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
[chapter-toggle] {
|
||||
|
@ -58,6 +58,7 @@
|
||||
flex-direction: column;
|
||||
border: 1px solid #DDD;
|
||||
width: 50%;
|
||||
max-width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,7 +98,6 @@ label {
|
||||
font-size: 0.94em;
|
||||
font-weight: 400;
|
||||
color: #999;
|
||||
text-transform: uppercase;
|
||||
padding-bottom: 2px;
|
||||
margin-bottom: 0.2em;
|
||||
&.inline {
|
||||
@ -191,6 +191,13 @@ input:checked + .toggle-switch {
|
||||
}
|
||||
}
|
||||
|
||||
.simple-code-input {
|
||||
background-color: #F8F8F8;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
.text-pos, .text-neg {
|
||||
padding: $-xs 0;
|
||||
@ -315,4 +322,4 @@ div[editor-type="markdown"] .title-input.page-title input[type="text"] {
|
||||
|
||||
.image-picker img {
|
||||
background-color: #BBB;
|
||||
}
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ header .search-box {
|
||||
|
||||
@include smaller-than($m) {
|
||||
.breadcrumbs .text-button, .action-buttons .text-button {
|
||||
padding: $-s $-xs;
|
||||
padding: $-xs $-xs;
|
||||
}
|
||||
.action-buttons .dropdown-container:last-child a {
|
||||
padding-left: $-xs;
|
||||
@ -218,6 +218,9 @@ header .search-box {
|
||||
.breadcrumbs .text-button {
|
||||
font-size: 0;
|
||||
}
|
||||
.breadcrumbs .text-button svg {
|
||||
font-size: $fs-m;
|
||||
}
|
||||
.breadcrumbs a i {
|
||||
font-size: $fs-m;
|
||||
padding-right: 0;
|
||||
@ -225,6 +228,9 @@ header .search-box {
|
||||
.breadcrumbs span.sep {
|
||||
padding: 0 $-xxs;
|
||||
}
|
||||
.toolbar .col-xs-1:first-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
|
@ -55,6 +55,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
@include smaller-than($s) {
|
||||
.page-list h4 {
|
||||
font-size: 1.333em;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-page-nav {
|
||||
$nav-indent: $-s;
|
||||
list-style: none;
|
||||
|
@ -2,6 +2,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
overflow: hidden;
|
||||
.faded-small {
|
||||
height: auto;
|
||||
}
|
||||
|
@ -61,6 +61,24 @@ h5, h6 {
|
||||
margin-bottom: 0.66em;
|
||||
}
|
||||
|
||||
@include smaller-than($s) {
|
||||
h1 {
|
||||
font-size: 2.8275em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 2.333em;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.666em;
|
||||
}
|
||||
h4 {
|
||||
font-size: 1.333em;
|
||||
}
|
||||
h5 {
|
||||
font-size: 1.161616em;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Link styling
|
||||
*/
|
||||
@ -374,8 +392,8 @@ li.checkbox-item, li.task-list-item {
|
||||
}
|
||||
|
||||
.break-text {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,6 +10,10 @@
|
||||
@import "lists";
|
||||
@import "pages";
|
||||
|
||||
body {
|
||||
font-family: 'DejaVu Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Roboto", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
|
@ -19,7 +19,7 @@ return [
|
||||
'app_settings' => 'App Settings',
|
||||
'app_name' => 'Application name',
|
||||
'app_name_desc' => 'This name is shown in the header and any emails.',
|
||||
'app_name_header' => 'Show Application name in header?',
|
||||
'app_name_header' => 'Show application name in header?',
|
||||
'app_public_viewing' => 'Allow public viewing?',
|
||||
'app_secure_images' => 'Enable higher security image uploads?',
|
||||
'app_secure_images_desc' => 'For performance reasons, all images are public. This option adds a random, hard-to-guess string in front of image urls. Ensure directory indexes are not enabled to prevent easy access.',
|
||||
@ -31,7 +31,7 @@ return [
|
||||
'app_logo_desc' => 'This image should be 43px in height. <br>Large images will be scaled down.',
|
||||
'app_primary_color' => 'Application primary color',
|
||||
'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.',
|
||||
'app_homepage' => 'Application Homepage',
|
||||
'app_homepage' => 'Application homepage',
|
||||
'app_homepage_desc' => 'Select a page to show on the homepage instead of the default view. Page permissions are ignored for selected pages.',
|
||||
'app_homepage_default' => 'Default homepage view chosen',
|
||||
'app_disable_comments' => 'Disable comments',
|
||||
|
@ -18,6 +18,8 @@ return [
|
||||
'name' => 'Nome',
|
||||
'description' => 'Descrizione',
|
||||
'role' => 'Ruolo',
|
||||
'cover_image' => 'Immagine di copertina',
|
||||
'cover_image_description' => 'Questa immagine dovrebbe essere approssimatamente 440x250px.',
|
||||
|
||||
/**
|
||||
* Actions
|
||||
@ -45,7 +47,10 @@ return [
|
||||
'no_items' => 'Nessun elemento disponibile',
|
||||
'back_to_top' => 'Torna in alto',
|
||||
'toggle_details' => 'Mostra Dettagli',
|
||||
'toggle_thumbnails' => 'Mostra Miniature',
|
||||
'details' => 'Dettagli',
|
||||
'grid_view' => 'Visualizzazione Griglia',
|
||||
'list_view' => 'Visualizzazione Lista',
|
||||
|
||||
/**
|
||||
* Header
|
||||
|
@ -162,6 +162,7 @@ return [
|
||||
'pages_md_preview' => 'Anteprima',
|
||||
'pages_md_insert_image' => 'Inserisci Immagina',
|
||||
'pages_md_insert_link' => 'Inserisci Link Entità',
|
||||
'pages_md_insert_drawing' => 'Inserisci Disegno',
|
||||
'pages_not_in_chapter' => 'La pagina non è in un capitolo',
|
||||
'pages_move' => 'Muovi Pagina',
|
||||
'pages_move_success' => 'Pagina mossa in ":parentName"',
|
||||
@ -244,6 +245,7 @@ return [
|
||||
*/
|
||||
'comment' => 'Commento',
|
||||
'comments' => 'Commenti',
|
||||
'comment_add' => 'Aggiungi Commento',
|
||||
'comment_placeholder' => 'Scrivi un commento',
|
||||
'comment_count' => '{0} Nessun Commento|{1} 1 Commento|[2,*] :count Commenti',
|
||||
'comment_save' => 'Salva Commento',
|
||||
|
@ -20,6 +20,7 @@ return [
|
||||
'ldap_extension_not_installed' => 'L\'estensione PHP LDAP non è installata',
|
||||
'ldap_cannot_connect' => 'Impossibile connettersi al server ldap, connessione iniziale fallita',
|
||||
'social_no_action_defined' => 'Nessuna azione definita',
|
||||
'social_login_bad_response' => "Ricevuto error durante il login con :socialAccount : \n:error",
|
||||
'social_account_in_use' => 'Questo account :socialAccount è già utilizzato, prova a loggarti usando l\'opzione :socialAccount.',
|
||||
'social_account_email_in_use' => 'La mail :email è già in uso. Se hai già un account puoi connettere il tuo account :socialAccount dalle impostazioni del tuo profilo.',
|
||||
'social_account_existing' => 'Questo account :socialAccount è già connesso al tuo profilo.',
|
||||
@ -35,12 +36,15 @@ return [
|
||||
'cannot_create_thumbs' => 'Il server non può creare thumbnail. Controlla che l\'estensione GD sia installata.',
|
||||
'server_upload_limit' => 'Il server non permette un upload di questa grandezza. Prova con un file più piccolo.',
|
||||
'image_upload_error' => 'C\'è stato un errore caricando l\'immagine',
|
||||
'image_upload_type_error' => 'Il tipo di immagine in upload non è valido',
|
||||
|
||||
// Attachments
|
||||
'attachment_page_mismatch' => 'Page mismatch during attachment update',
|
||||
'attachment_not_found' => 'Allegato non trovato',
|
||||
|
||||
// Pages
|
||||
'page_draft_autosave_fail' => 'Impossibile salvare la bozza. Controlla di essere connesso ad internet prima di salvare questa pagina',
|
||||
'page_custom_home_deletion' => 'Impossibile eliminare una pagina quando è impostata come homepage',
|
||||
|
||||
// Entities
|
||||
'entity_not_found' => 'Entità non trovata',
|
||||
|
@ -40,6 +40,7 @@ return [
|
||||
/**
|
||||
* Registration settings
|
||||
*/
|
||||
|
||||
'reg_settings' => 'Impostazioni Registrazione',
|
||||
'reg_allow' => 'Consentire Registrazione?',
|
||||
'reg_default_role' => 'Ruolo predefinito dopo la registrazione',
|
||||
|
@ -10,12 +10,10 @@
|
||||
<meta charset="utf-8">
|
||||
|
||||
<!-- Styles and Fonts -->
|
||||
<link rel="stylesheet" href="{{ versioned_asset('css/styles.css') }}">
|
||||
<link rel="stylesheet" media="print" href="{{ versioned_asset('css/print-styles.css') }}">
|
||||
<link rel="stylesheet" href="{{ versioned_asset('dist/styles.css') }}">
|
||||
<link rel="stylesheet" media="print" href="{{ versioned_asset('dist/print-styles.css') }}">
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="{{ baseUrl('/libs/jquery/jquery.min.js?version=2.1.4') }}"></script>
|
||||
<script src="{{ baseUrl('/libs/jquery/jquery-ui.min.js?version=1.11.4') }}"></script>
|
||||
<script src="{{ baseUrl('/translations') }}"></script>
|
||||
|
||||
@yield('head')
|
||||
@ -82,7 +80,7 @@
|
||||
</div>
|
||||
</div>
|
||||
@yield('bottom')
|
||||
<script src="{{ versioned_asset('js/common.js') }}"></script>
|
||||
<script src="{{ versioned_asset('dist/app.js') }}"></script>
|
||||
@yield('scripts')
|
||||
</body>
|
||||
</html>
|
||||
|
@ -91,8 +91,8 @@
|
||||
|
||||
@section('body')
|
||||
|
||||
<div class="container small">
|
||||
<h1>{{$book->name}}</h1>
|
||||
<div class="container small nopad">
|
||||
<h1 class="break-text" v-pre>{{$book->name}}</h1>
|
||||
<div class="book-content" v-show="!searching">
|
||||
<p class="text-muted" v-pre>{!! nl2br(e($book->description)) !!}</p>
|
||||
@if(count($bookChildren) > 0)
|
||||
|
@ -1,9 +1,5 @@
|
||||
@extends('simple-layout')
|
||||
|
||||
@section('head')
|
||||
<script src="{{ baseUrl("/libs/jquery-sortable/jquery-sortable.min.js") }}"></script>
|
||||
@stop
|
||||
|
||||
@section('toolbar')
|
||||
<div class="col-sm-12 faded">
|
||||
@include('books._breadcrumbs', ['book' => $book])
|
||||
@ -52,11 +48,12 @@
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('scripts')
|
||||
<script src="{{ baseUrl("/libs/jquery-sortable/jquery-sortable.min.js") }}"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
|
@ -96,8 +96,8 @@
|
||||
|
||||
@section('body')
|
||||
|
||||
<div class="container small">
|
||||
<h1 v-pre>{{ $chapter->name }}</h1>
|
||||
<div class="container small nopad">
|
||||
<h1 class="break-text" v-pre>{{ $chapter->name }}</h1>
|
||||
<div class="chapter-content" v-show="!searching">
|
||||
<p v-pre class="text-muted break-text">{!! nl2br(e($chapter->description)) !!}</p>
|
||||
|
||||
|
@ -1,15 +1,4 @@
|
||||
<div toggle-switch="{{$name}}" class="toggle-switch @if($value) active @endif">
|
||||
<input type="hidden" name="{{$name}}" value="{{$value?'true':'false'}}"/>
|
||||
<div class="switch-handle"></div>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
var toggle = document.querySelector('[toggle-switch="{{$name}}"]');
|
||||
var toggleInput = toggle.querySelector('input');
|
||||
toggle.onclick = function(event) {
|
||||
var checked = toggleInput.value !== 'true';
|
||||
toggleInput.value = checked ? 'true' : 'false';
|
||||
checked ? toggle.classList.add('active') : toggle.classList.remove('active');
|
||||
};
|
||||
})()
|
||||
</script>
|
||||
</div>
|
@ -6,7 +6,7 @@
|
||||
|
||||
<style>
|
||||
@if (!app()->environment('testing'))
|
||||
{!! file_get_contents(public_path('/css/export-styles.css')) !!}
|
||||
{!! file_get_contents(public_path('/dist/export-styles.css')) !!}
|
||||
@endif
|
||||
</style>
|
||||
@yield('head')
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div ng-non-bindable>
|
||||
|
||||
<h1 id="bkmrk-page-title">{{$page->name}}</h1>
|
||||
<h1 class="break-text" v-pre id="bkmrk-page-title">{{$page->name}}</h1>
|
||||
|
||||
<div style="clear:left;"></div>
|
||||
|
||||
|
@ -10,8 +10,8 @@
|
||||
<meta charset="utf-8">
|
||||
|
||||
<!-- Styles and Fonts -->
|
||||
<link rel="stylesheet" href="{{ versioned_asset('css/styles.css') }}">
|
||||
<link rel="stylesheet" media="print" href="{{ versioned_asset('css/print-styles.css') }}">
|
||||
<link rel="stylesheet" href="{{ versioned_asset('dist/styles.css') }}">
|
||||
<link rel="stylesheet" media="print" href="{{ versioned_asset('dist/print-styles.css') }}">
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="{{ baseUrl("/libs/jquery/jquery.min.js?version=2.1.4") }}"></script>
|
||||
@ -58,6 +58,6 @@
|
||||
@yield('content')
|
||||
</section>
|
||||
|
||||
<script src="{{ versioned_asset('js/common.js') }}"></script>
|
||||
<script src="{{ versioned_asset('dist/app.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -88,7 +88,7 @@
|
||||
<div class="form-group">
|
||||
<label for="setting-app-custom-head">{{ trans('settings.app_custom_html') }}</label>
|
||||
<p class="small">{{ trans('settings.app_custom_html_desc') }}</p>
|
||||
<textarea name="setting-app-custom-head" id="setting-app-custom-head">{{ setting('app-custom-head', '') }}</textarea>
|
||||
<textarea class="simple-code-input" name="setting-app-custom-head" id="setting-app-custom-head">{{ setting('app-custom-head', '') }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group text-right">
|
||||
|
@ -112,4 +112,31 @@ class PageContentTest extends TestCase
|
||||
$pageView->assertSee('def456');
|
||||
}
|
||||
|
||||
public function test_page_content_scripts_escaped_by_default()
|
||||
{
|
||||
$this->asEditor();
|
||||
$page = Page::first();
|
||||
$script = '<script>console.log("hello-test")</script>';
|
||||
$page->html = "escape {$script}";
|
||||
$page->save();
|
||||
|
||||
$pageView = $this->get($page->getUrl());
|
||||
$pageView->assertDontSee($script);
|
||||
$pageView->assertSee(htmlentities($script));
|
||||
}
|
||||
|
||||
public function test_page_content_scripts_show_when_configured()
|
||||
{
|
||||
$this->asEditor();
|
||||
$page = Page::first();
|
||||
config()->push('app.allow_content_scripts', 'true');
|
||||
$script = '<script>console.log("hello-test")</script>';
|
||||
$page->html = "no escape {$script}";
|
||||
$page->save();
|
||||
|
||||
$pageView = $this->get($page->getUrl());
|
||||
$pageView->assertSee($script);
|
||||
$pageView->assertDontSee(htmlentities($script));
|
||||
}
|
||||
|
||||
}
|
||||
|
71
webpack.config.js
Normal file
71
webpack.config.js
Normal file
@ -0,0 +1,71 @@
|
||||
const path = require('path');
|
||||
const dev = process.env.NODE_ENV !== 'production';
|
||||
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const ExtractTextPlugin = require("extract-text-webpack-plugin");
|
||||
|
||||
const config = {
|
||||
target: 'web',
|
||||
mode: dev? 'development' : 'production',
|
||||
entry: {
|
||||
app: './resources/assets/js/index.js',
|
||||
styles: './resources/assets/sass/styles.scss',
|
||||
"export-styles": './resources/assets/sass/export-styles.scss',
|
||||
"print-styles": './resources/assets/sass/print-styles.scss',
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
path: path.resolve(__dirname, 'public/dist')
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /(node_modules)/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['@babel/preset-env']
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: ExtractTextPlugin.extract({
|
||||
fallback: "style-loader",
|
||||
use: [{
|
||||
loader: "css-loader", options: {
|
||||
sourceMap: dev
|
||||
}
|
||||
}, {
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
ident: 'postcss',
|
||||
sourceMap: dev,
|
||||
plugins: (loader) => [
|
||||
require('autoprefixer')(),
|
||||
]
|
||||
}
|
||||
}, {
|
||||
loader: "sass-loader", options: {
|
||||
sourceMap: dev
|
||||
}
|
||||
}]
|
||||
})
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new ExtractTextPlugin("[name].css"),
|
||||
]
|
||||
};
|
||||
|
||||
if (dev) {
|
||||
config['devtool'] = 'inline-source-map';
|
||||
}
|
||||
|
||||
if (!dev) {
|
||||
config.plugins.push(new UglifyJsPlugin());
|
||||
}
|
||||
|
||||
module.exports = config;
|
Loading…
Reference in New Issue
Block a user