use App\Models\FluidbookPublication;
use App\Models\User;
use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;
use Cubist\Util\Files\Files;
Route::match(['get'], $segment . '/{id}/markdown', $controller . '@getFilesById');
Route::match(['put'], $segment . '/{id}/save/markdown', $controller . '@saveMarkdown');
Route::match(['get'], $segment . '/{id}/import/markdown', $controller . '@importMarkdown');
+ Route::match(['post'], $segment . '/{id}/edit/markdown/move', $controller . '@moveMarkdown');
}
public function markdown($id)
return response()->json(['success' => $md['pages']]);
}
+
+ protected function moveMarkdown($fluidbook_id) {
+ if (!FluidbookPublication::hasPermission($fluidbook_id)) {
+ abort(401);
+ }
+
+ $offset = intval(request('number', 1));
+ $from = intval(request('start', 0));
+
+ $markdown = $this->getLatestMarkdown($fluidbook_id)['pages'];
+
+ $newOrder = [];
+ $newKey = 1;
+
+ $newOrder = array_slice($markdown, 0, $from > 1 ? $from - 1 : $from,true);
+ $markdown = array_slice($markdown, $from > 1 ? $from - 1 : $from, count($markdown), true);
+
+ foreach ($markdown as $k => $m) {
+
+ if ($offset < 0) {
+ $k -= abs($offset);
+ } else {
+ $k += $offset;
+ }
+
+ if(!array_key_exists($newKey,$newOrder)) {
+ $newOrder[$newKey] = "";
+ }
+
+ $newOrder["".$k] = $m;
+ $newKey++;
+ }
+
+ ksort($newOrder);
+
+ $this->saveMarkdown($fluidbook_id, __('Décalage de :nb pages à partir de la page :page', ['nb' => $offset, 'page' => $from, 'date' => date('Y-m-d H:i:s')]), $newOrder);
+ return Redirect::back();
+ }
}
import MarkdowneditorSave from "./markdowneditor.save";
import MarkdowneditorVersions from "./markdowneditor.versions";
import MarkdowneditorZoom from "./markdowneditor.zoom";
+import MarkdowneditorPopup from "./markdowneditor.popup";
+import MarkdowneditorResize from "./markdowneditor.resize";
import tippy from "tippy.js";
import 'tippy.js/dist/tippy.css';
import Noty from "noty";
import 'noty/lib/noty.css';
import 'noty/lib/themes/mint.css';
+import LinkeditorPopup from "../../linkeditor/js/linkeditor.popup";
window.$ = window.jQuery = require('jquery');
window.key = require('keymaster-reloaded');
init: function() {
new MarkdowneditorToolbar(this);
this.undo = new MarkdowneditorUndo(this);
+ this.resize = new MarkdowneditorResize(this);
this.save = new MarkdowneditorSave(this);
this.versions = new MarkdowneditorVersions(this);
this.zoom = new MarkdowneditorZoom(this);
+ this.popup = new MarkdowneditorPopup(this);
this.options = {
el: document.querySelector('#editor'),
--- /dev/null
+function MarkdowneditorPopup(markdowneditor) {
+ this.markdowneditor = markdowneditor;
+ this.init();
+}
+
+MarkdowneditorPopup.prototype = {
+ init: function () {
+ var $this = this;
+ $(document).on('click', '.popup .close', function () {
+ if ($this.hasOpenPopup()) {
+ $this.close();
+ }
+ });
+ },
+
+ openLinksMove() {
+ this.open('moveLinks');
+ },
+
+ open: function (name) {
+ var clone = $("#popup-templates [data-popup=" + name + "]").clone();
+ $("#popup-holder").append(clone);
+ $("#popup-overlay").addClass('show');
+ this.resize();
+ },
+
+ close: function (name = '') {
+ $("#popup-overlay").removeClass('show');
+ $("#popup-holder").html('');
+ },
+
+ hasOpenPopup() {
+ return $("#popup-overlay.show").length === 1;
+ },
+
+ resize: function () {
+ if (!this.hasOpenPopup()) {
+ return;
+ }
+ var p = $("#popup-holder>div");
+ var w = $(p).outerWidth();
+ var h = $(p).outerHeight();
+ var left = (this.markdowneditor.resize.ww - w) / 2;
+ var top = (this.markdowneditor.resize.hh - h) / 2;
+ $("#popup-holder").css({
+ width: w,
+ height: h,
+ left: left,
+ top: top,
+ })
+ }
+};
+export default MarkdowneditorPopup;
--- /dev/null
+function MarkdowneditorResize(markdowneditor) {
+ this.markdowneditor = markdowneditor;
+ this.init();
+}
+
+MarkdowneditorResize.prototype = {
+ init: function () {
+ var $this = this;
+ $(window).on('resize', function () {
+ $this.resize();
+ setTimeout(function () {
+ $this.resize();
+ }, 100);
+ });
+ this.updateWindowDimensions();
+ },
+
+ updateWindowDimensions: function () {
+ this.ww = $(window).outerWidth();
+ this.hh = $(window).outerHeight();
+ },
+
+ resize: function () {
+ let special = this.markdowneditor.utils.isSpecialPage();
+ if (this.markdowneditor.single || special) {
+ $("#markdowneditor").addClass('single').removeClass('double');
+ } else {
+ $("#markdowneditor").addClass('double').removeClass('single');
+ }
+ this.resizePages();
+ this.updateWindowDimensions();
+ this.resizeMain();
+ this.resizeCanvas();
+ if (this.markdowneditor.panels) {
+ this.markdowneditor.panels.resize(this.ww);
+ }
+ this.markdowneditor.rulers.updateRulers();
+ if (this.markdowneditor.popup) {
+ this.markdowneditor.popup.resize();
+ }
+ let width = $("#markdowneditor-fluidbook").css("width")
+ let height = $("#markdowneditor-fluidbook").css("height")
+ let transform = $("#markdowneditor-fluidbook").css("transform")
+ let left_ = $("#markdowneditor-fluidbook").css("left")
+ let top_ = $("#markdowneditor-fluidbook").css("top")
+
+ $("#markdowneditor-layer-links").css({
+ 'width':width,
+ 'height':height,
+ 'left':left_,
+ 'top':top_,
+ 'transform':transform,
+ })
+ //this.markdowneditor.previewLinks.setPreview()
+ },
+
+ resizePages: function () {
+ let $this = this;
+ let dimCover = $this.markdowneditor.utils.getPageDimensions(1);
+ let pw;
+ let ph;
+ let special = false;
+
+ $(".markdowneditor-page[data-page]:visible").each(function () {
+ let p = $(this).attr('data-page');
+ let dim = $this.markdowneditor.utils.getPageDimensions(p);
+ if (dim === undefined) {
+ dim = dimCover;
+ }
+ pw = dim[0];
+ ph = dim[1];
+
+ if ($this.markdowneditor.utils.isSpecialPage(p)) {
+ special = true;
+ } else if ($this.markdowneditor.mobileFirst) {
+ pw = dimCover[0];
+ } else {
+ pw = dimCover[0];
+ ph = dimCover[1];
+ }
+ $(this).css({width: pw, height: ph});
+ });
+
+ let fw = pw;
+ if (!this.markdowneditor.single && !special) {
+ fw *= 2;
+ }
+ $("#markdowneditor-page-right").css({left: this.markdowneditor.pw});
+ $("#markdowneditor-fluidbook,#markdowneditor-layer-links,.markdowneditor-fluidbook-copy").css({width: fw, height: ph});
+ },
+
+ resizeMain: function () {
+ $("#markdowneditor-main").css('width', this.ww - $('#markdowneditor-left').outerWidth() - $('#markdowneditor-right').outerWidth());
+ },
+
+ resizeCanvas: function () {
+ this.markdowneditor.canvasRect = $("#markdowneditor-canvas").get(0).getBoundingClientRect();
+ this.markdowneditor.editorRect = $("#markdowneditor-editor").get(0).getBoundingClientRect();
+ var aw = this.markdowneditor.canvasRect.width - 30;
+ var ah = this.markdowneditor.canvasRect.height - 30;
+
+ if (this.markdowneditor.utils.isSpecialPage()) {
+ let dim = this.markdowneditor.utils.getPageDimensions();
+ this.markdowneditor.fs = Math.min(1, aw / dim[0], ah / dim[1]);
+ } else if (this.markdowneditor.mobileFirst) {
+ this.markdowneditor.fs = 620 / this.markdowneditor.fw;
+ } else {
+ this.markdowneditor.fs = Math.min(aw / this.markdowneditor.fw, ah / this.markdowneditor.fh);
+ }
+
+ let left, top;
+
+ if (this.markdowneditor.utils.isSpecialPage()) {
+ let dim = this.markdowneditor.utils.getPageDimensions();
+ left = (this.markdowneditor.canvasRect.width - (dim[0] * this.markdowneditor.fs)) / 2;
+ top = (this.markdowneditor.canvasRect.height - (dim[1] * this.markdowneditor.fs)) / 2;
+ } else if (!this.markdowneditor.mobileFirst) {
+ left = ((this.markdowneditor.canvasRect.width * 2) - this.markdowneditor.fw * this.markdowneditor.fs) / 2;
+ top = ((this.markdowneditor.canvasRect.height * 2) - this.markdowneditor.fh * this.markdowneditor.fs) / 2;
+ } else {
+ left = (this.markdowneditor.canvasRect.width - this.markdowneditor.fw * this.markdowneditor.fs) / 2;
+ top = 75;
+ }
+ $("#markdowneditor-fluidbook,#markdowneditor-layer-links").css({left: left, top: top, transform: 'scale(' + this.markdowneditor.fs + ')'});
+ },
+};
+export default MarkdowneditorResize;
--- /dev/null
+body
+ --form-text-color: #5d5d5d
+ --field-background: #fff
+ --field-color: #bbb
+ --field-border: #aaa
+ --field-border-background: #fff
+ --field-color-button: #bbb
+ --field-border-button: #aaa
+
+ @include dark-theme
+ --form-text-color: #aaa
+ --field-background: #fff
+ --field-color: #bbb
+ --field-border: #ccc
+ --field-background-button: #000
+ --field-color-button: #ccc
+ --field-border-button: #bbb
+
+textarea, input[type="text"], input[type="number"], input[type="email"], input[type="url"], input[type="tel"]
+ font-family: $font
+ font-weight: 400
+ color: var(--field-color)
+ background-color: var(--field-background)
+ border: 1px solid var(--field-border)
+ border-radius: 3px
+ font-size: 13px
+ transition: box-shadow 500ms, border 500ms
+ appearance: none
+
+ &:focus
+ border: 1px solid var(--field-border)
+ box-shadow: 0 0 8px rgba(0, 0, 0, 0.3)
+
+input[type="checkbox"]
+ margin-right: 8px
+ appearance: none
+ position: relative
+ cursor: pointer
+ color: var(--form-text-color)
+
+ &::before
+ content: ''
+ display: inline-block
+ width: 14px
+ height: 14px
+ border: 1px solid currentColor
+ border-radius: 2px
+ vertical-align: baseline
+
+ &:checked
+ &::after
+ content: ''
+ display: block
+ width: 12px
+ height: 12px
+ position: absolute
+ top: 1px
+ left: 1px
+ clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%)
+ background-color: currentColor
+
+
+input[type=number]
+ &, &:hover
+ appearance: textfield
+
+ &::-webkit-inner-spin-button, &::-webkit-outer-spin-button
+ -webkit-appearance: none
+ margin: 0
+ visibility: hidden
+
+button
+ font-family: $font
+ font-weight: 500
+ font-size: 15px
+ padding: 5px 10px
+ border: 1px solid var(--field-border-button)
+ border-radius: 4px
+ color: var(--field-color-button)
+ background-color: var(--field-background-button)
+ cursor: pointer
+
+.select2-hidden-accessible
+ position: fixed !important
+
+#linkeditor-form-templates
+ display: none
+
+.linkeditor-linktype
+ &::before
+ display: inline-block
+ width: 12px
+ height: 12px
+ border-radius: 2px
+ margin: 2px 10px 0 0
+ content: ""
+ vertical-align: top
+ position: relative
+
+
+#linkeditor-panel-form
+
+
+ padding: 12px
+ font-size: 13px
+
+ .select2-container--bootstrap
+ font-size: 13px
+ font-weight: 400
+
+ hr
+ border: 0
+ height: 1px
+ background-color: var(--form-text-color)
+ margin: 5px 0
+
+ &, .select2-selection
+ color: var(--form-text-color)
+ background-color: var(--field-background)
+ border-color: var(--field-background)
+ border-radius: 4px
+ box-shadow: none
+
+ &.select2-container--focus .select2-selection, &.select2-container--open .select2-selection
+ box-shadow: 0 0 8px rgba(0, 0, 0, 0.1)
+ border-color: var(--field-border)
+
+ h3
+ font-size: 16px
+ color: var(--form-text-color)
+ text-transform: uppercase
+ padding-top: 15px
+ border-top: 1px solid var(--form-text-color)
+ margin-top: 20px
+
+ p.help-block
+ color: var(--form-text-color)
+ font-size: 11px
+ padding-top: 2px
+ white-space: normal
+
+ .freefile-file
+ position: relative
+
+ &.loading
+ &::after
+ background-image: url("/images/linkeditor/dots-animated.svg")
+ @include dark-theme
+ background-image: url("/images/linkeditor/dots-dark-animated.svg")
+
+ input
+ pointer-events: none
+ cursor: wait
+
+ &::after
+ content: ""
+ position: absolute
+ display: block
+ padding: 6px
+ right: 0
+ top: 6px
+ width: 25px
+ height: 25px
+ background-image: url("/images/linkeditor/dots.svg")
+ color: var(--field-color)
+ box-sizing: border-box
+ pointer-events: none
+ font-size: 17px
+ @include dark-theme
+ background-image: url("/images/linkeditor/dots-dark.svg")
+
+ input[type=file]
+ position: absolute
+ right: 0
+ width: 35px
+ opacity: 0
+ height: 100%
+ cursor: pointer
+
+ a.upload
+ position: absolute
+ right: 0
+ width: 35px
+ opacity: 0
+ height: 100%
+ cursor: pointer
+ z-index: 2
+
+
+ .input-group
+ position: relative
+
+ .input-group-append
+ position: absolute
+ height: 100%
+ top: 0
+ right: 0
+ pointer-events: none
+ padding: 8px
+
+ textarea, input[type="text"], input[type="number"], input[type="email"], input[type="url"], input[type="tel"]
+ height: 34px
+ padding: 8px
+ width: 100%
+
+ textarea
+ height: auto
+ min-height: 150px
+ max-width: 100%
+ min-width: 100%
+
+ span
+ font-weight: 400
+ font-size: 13px
+ color: var(--form-text-color)
+
+ label
+ display: block
+ font-weight: 600
+ font-size: 12px
+ color: var(--form-text-color)
+ margin: 8px 0 5px 0
+
+ .checkbox
+ margin: 4px 0 5px 0
+
+ position: relative
+ top: 6px
+
+ label
+ vertical-align: baseline
+ display: inline-block
+ position: relative
+ top: -4px
+ margin: 0
+ cursor: pointer
+
+ span
+ margin-left: 5px
+
+
+ #group_position, #group_dimensions, #group_transform
+ margin-top: 5px
+
+ h4
+ font-size: 12px
+ font-weight: 700
+ color: var(--form-text-color)
+ grid-column: 1 / 3
+ grid-row: 1 / 2
+ margin-bottom: 5px
+
+ display: grid
+ grid-template-columns: repeat( 2, 1fr)
+ grid-gap: 2px 25px
+
+ label
+ display: inline-block
+ width: 20px
+
+ input
+ width: calc(100% - 20px)
+
+ [data-name="rot"]
+ label
+ display: block
+
+ .input-group
+ .input-group-append
+ right: 0
+
+ .input-group
+ display: inline-block
+
+ .input-group-append
+ right: 20px
+
+
+ #group_transform
+ input
+ width: 100%
+
+.select2-container--bootstrap .select2-results > .select2-results__options
+ max-height: 350px !important
+
+
+[data-name='image_rollover'] label
+ display: flex !important
+ align-items: end
+ justify-content: space-between
+
+#linkeditor-start-animation
+ display: flex
+ width: 26px
+ height: 26px
+ background: transparent
+ padding: 4px 4px
+ border: 0
+ &:hover
+ background-color: #000
+ svg
+ width: 100%
+ fill: transparent
--- /dev/null
+#popup-templates
+ display: none
+
+#popup-overlay
+ background-color: rgba(0, 0, 0, 0.5)
+ position: absolute
+ top: 0
+ left: 0
+ opacity: 0
+ pointer-events: none
+ transition: opacity 350ms
+ width: 100%
+ height: 100%
+ z-index: 10000000
+
+ &.show,
+ &.unavailable
+ opacity: 1
+ pointer-events: auto
+
+ #popup-holder
+ position: absolute
+ max-width: 100%
+ max-height: 100%
+
+ .popup
+ background-color: #dbdddf
+ color: #5D5D5D
+ font-size: 13px
+ padding: 20px
+ box-shadow: 0 0 20px rgba(0,0,0,0.5)
+
+ h2
+ font-size: 16px
+ padding-bottom: 10px
+ font-weight: 500
+ margin: 0
+
+ a.close
+ display: block
+ position: absolute
+ top: 20px
+ right: 20px
+ width: 15px
+ height: 15px
+ cursor: pointer
+
+ p
+ margin: 12px 0
+ white-space: normal
+
+ p.button
+ text-align: right
+ margin: 20px 0 0 0
+
+
+ @include dark-theme
+ background-color: #333
+ color: #d5d5d5
+
+ &[data-popup="moveLinks"]
+ input
+ &[type="text"],&[type="number"]
+ width: 50px
+ height: 20px
+ margin: 0 5px
+ padding: 4px
--- /dev/null
+$font: Montserrat, sans-serif
+$font-size: 16px
+$sidebar-icons-width: 46px
+$sidebar-handle-width: 3px
+$rulers-size: 16px
+$ruler-margin: 2px
+
+$toolbar-height: 40px
+$toolbar-color: #5d5d5d
+$toolbar-color-dark: #bbb
+
+$toolbar-color-disabled: #bbb
+$toolbar-color-disabled-dark: #666
+
+$panel-background: #dcdcdc
+
+$color: #5d5d5d
+$color-dark: #bbb
@include dark-theme
background-color: #222 !important
border-top-color: #222 !important
+
+@import "inc/_variables"
+@import "inc/_form"
+@import "inc/_popup"
@section('content')
@include('fluidbook_publication.link_editor_icons')
+ <div id="popup-overlay">
+ <div id="popup-holder">
+ </div>
+ </div>
+ <div id="popup-templates">
+ <div class="popup" data-popup="moveLinks" style="max-width: 300px">
+ <h2>{{__('Déplacer le contenu')}}</h2>
+ <a nohref="" class="close" data-icon="close"></a>
+ <form action="/fluidbook-publication/{{$fbdata['id']}}/edit/markdown/move"
+ data-save-before-submit="{{__("Sauvegarde avant le déplacement de liens")}}"
+ class="reloadAfterSuccess" method="post">
+ @csrf
+ <p>{!! __('Déplacer le contenu de :nb pages :br à partir de la page :page',
+ ['br'=>'</p><p>','nb'=>'<input type="number" name="number">','page'=>'<input type="text" name="start">'])!!}</p>
+ <p class="button">
+ <button type="submit">{{__('Déplacer le contenu')}}</button>
+ </p>
+ </form>
+ </div>
+ </div>
<div class="markdown">
<div id="markdown-revision" class="markdown-revision">
<div class="markdown-revision-nav">
<a href="#" id="linkeditor-icon-versions" data-panel="form" data-icon="wayback-machine"
data-action="toggleRevisions"
- data-tooltip="{{__('Restaurer une version précédente')}} (F8)" data-key="f8"></a>
+ data-tooltip="{{__('Paramètres du lien')}} (F8)" data-key="f8"></a>
</div>
<div class="markdown-revision-panel">
<div id="markdown-panel-versions">
<div class="markdown-editor">
<div class="markdown-nav markdown-toolbar">
<nav class="markdown-toolbar-left" id="markdown-toolbar-left">
- <div class="markdown-toolbar-save-block">
+ <div class="loading-block markdown-toolbar-save-block">
<a href="#" data-icon="save" data-action="save.save" data-tooltip="{{__('Sauvegarder')}} (Ctrl+S)"
- ></a>
+ data-key="ctrl+s"></a>
<a nohref data-icon="loading" class=""></a>
</div>
<a href="#" data-icon="undo" data-action="undo.undo"
<div class="separator"></div>
</nav>
<nav class="markdown-toolbar-center" id="markdown-toolbar-center">
+ <a href="#" data-action="popup.openLinksMove" data-icon="move-links"
+ data-tooltip="{{__('Déplacer les liens')}}" tabindex="-1"></a>
<a href="#" data-action="firstPage" data-icon="first-page"
data-tooltip="{{__('Aller à la couverture')}}"></a>
<a href="#" data-action="previousPage" data-icon="previous-page"
<a href="#" data-action="lastPage" data-icon="last-page"
data-tooltip="{{__('Aller à la dernière page')}}"></a>
<div class="separator"></div>
- <a href="#" data-action="importMarkdown" data-icon="import-markdown"
- data-tooltip="{{__('Réimporter les contenus à partir du PDF')}}"></a>
+ <div class="loading-block">
+ <a href="#" data-action="importMarkdown" data-icon="import-markdown"
+ data-tooltip="{{__('Importer le markdown')}}"></a>
+ <a nohref data-icon="loading" class=""></a>
+ </div>
+ <div class="loading-block">
+ <a href="#" data-action="importSingleMarkdown" data-icon="import-single-markdown"
+ data-tooltip="{{__('Importer le markdown de la page courante')}}">
+ </a>
+ <a nohref data-icon="loading" class=""></a>
+ </div>
<a href="#" data-action="openFluidbook" data-icon="open-fluidbook"
data-tooltip="{{__('Ouvrir le fluidbook à la page courante')}}"></a>
</nav>