use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;
+use Cubist\Util\Files\Files;
trait MarkdownOperation
{
protected function setupMarkdownRoutes($segment, $routeName, $controller)
{
Route::match(['get'], $segment . '/{id}/edit/markdown', $controller . '@markdown')->name('fluidbook_markdowneditor');
- Route::match(['post'], $segment . '/{id}/markdown', $controller . '@getFilesById');
+ Route::match(['get'], $segment . '/{id}/markdown', $controller . '@getFilesById');
}
public function markdown($id)
}
$token = Str::random(10);
+ $files = $this->getFilesById($id);
- return view('fluidbook_publication.markdown_editor', ['version' => 'stable', 'id' => $id, 'fluidbook' => FluidbookPublication::find($id), 'access' => "", 'token' => $token]);
+ return view('fluidbook_publication.markdown_editor', ['files' => $files, 'version' => 'stable', 'id' => $id, 'fluidbook' => FluidbookPublication::find($id), 'access' => "", 'token' => $token]);
}
- public static function getFilesById(Request $request,$id)
+ public function getFilesById($id)
{
- $p = $request->page;
- $path = public_path("/markdown_files/$id/p$p.md");
+ //$p = $request->page;;
+ $files = Files::getRecursiveDirectoryIterator(public_path("/markdown_files/$id"), true);
- if(!file_exists($path)) return false;
+ return $files;
- return file_get_contents(public_path("/markdown_files/$id/p$p.md"));
+ //if(!file_exists($path)) return false;
+
+ //return file_get_contents(public_path("/markdown_files/$id/p$p.md"));
}
}
import Editor from '@toast-ui/editor';
import MarkdowneditorToolbar from "./markdowneditor.toolbar";
+import MarkdowneditorUndo from "./markdowneditor.undo";
window.$ = window.jQuery = require('jquery');
$.ajaxSetup({
this.noCache = '?t=' + (new Date(FLUIDBOOK_DATA.composition_updated_at)).getTime();
this.currentPage = Math.max(1,parseInt(window.location.hash.substring(1))) || 1;
this.editor = null;
+ this.contentMarkdown = null;
this.init()
}
MarkdownEditor.prototype = {
init: function() {
- this.toolbar = new MarkdowneditorToolbar(this);
+ new MarkdowneditorToolbar(this);
+ this.undo = new MarkdowneditorUndo(this);
const $this = this
this.initIcons();
this.markdown();
this.changePage();
+ this.undo.initState();
$(window).on('hashchange', function () {
/*if ($this.maskHashEvent) {
$(".handle").removeClass("dragging")
$("body").removeClass("user-select-none")
})
+
+ $(document).on('keyup', function (e) {
+ $this.undo.pushState()
+ console.log($this.undo.states)
+ })
},
initIcons: function () {
},
loadPage: function() {
- if (!this.single) {
- this.loadPageHtml(this.currentPage);
- }
-
+ this.loadPageHtml(this.currentPage);
this.setContentMarkdown()
},
return res;
},
+ getCurrentPage: function () {
+ return this.currentPage;
+ },
+
setContentMarkdown: function() {
const $this = this
- $.ajax({
- url: '/fluidbook-publication/' + FLUIDBOOK_DATA.id +'/markdown',
- type: 'post',
- data: {page:this.currentPage},
- success: function (response) {
- $this.editor.setMarkdown(response)
- $this.editor.moveCursorToStart(true)
- }
- });
+ if(this.undo.states[this.getCurrentPage()] !== undefined || this.undo.states[this.getCurrentPage()] === null) {
+ const state = this.undo.states[this.getCurrentPage()]
+ const lastKey = state.length;
+ this.editor.setMarkdown(state[lastKey])
+ this.editor.moveCursorToStart(true)
+ }else {
+ this.contentMarkdown = MARKDOWN_DATA["p"+this.currentPage]
+ this.editor.setMarkdown(this.contentMarkdown)
+ this.editor.moveCursorToStart(true)
+ }
},
markdown: function() {
this.editor.getMarkdown();
},
+ setCurrentState: function (state) {
+ this.editor.setMarkdown(state)
+ this.editor.moveCursorToStart(true)
+ },
+
changePage: function(page) {
if (page === undefined) {
let h = window.location.hash;
--- /dev/null
+function MarkdowneditorSave(linkeditor) {
+ this.linkeditor = linkeditor;
+ this.init();
+}
+
+MarkdowneditorSave.prototype = {
+ init: function () {
+ let $this = this;
+
+ this.automaticSaveFrequency = 1000 * 5 * 60;
+ this.unsavedChanges = false;
+ this.automaticSaveTimeout = null;
+ this.runningAutomaticSaveTimeout = false;
+
+ $(window).on('beforeunload', function () {
+ if ($this.unsavedChanges) {
+ return TRANSLATIONS.warning_unsaved_changes;
+ }
+ })
+ },
+
+ hasChanged: function () {
+ let $this = this;
+ this.unsavedChanges = true;
+ if (this.runningAutomaticSaveTimeout === false) {
+ this.runningAutomaticSaveTimeout = true;
+ this.automaticSaveTimeout = setTimeout(function () {
+ $this.automaticSave();
+ }, this.automaticSaveFrequency);
+ }
+ },
+
+ saveIfUnsavedChanges: function (message, notify, callback) {
+ if (this.unsavedChanges) {
+ this.save(message, false, function () {
+ setTimeout(function () {
+ callback();
+ }, 1000);
+ });
+ } else {
+ callback();
+ }
+ },
+
+ save: function (message, notify, callback) {
+ if (notify === undefined) {
+ notify = true;
+ }
+ if (callback === undefined) {
+ callback = function () {
+
+ };
+ }
+ var $this = this;
+ if (message === undefined) {
+ message = TRANSLATIONS.manual_save_message;
+ }
+
+ $.ajax({
+ url: '/fluidbook-publication/' + FLUIDBOOK_DATA.id + '/save/links', method: 'post', data: {
+ _method: 'put',
+ message: message,
+ rulers: JSON.stringify(window.RULERS),
+ links: JSON.stringify(window.LINKS),
+ },
+ success: function (data) {
+ if (notify) {
+ $this.linkeditor.notification(TRANSLATIONS.success_save);
+ }
+ clearTimeout($this.automaticSaveTimeout);
+ $this.unsavedChanges = false;
+ $this.runningAutomaticSaveTimeout = false;
+
+ window.ASSETS = data.assets;
+ $this.linkeditor.versions.setVersions(data.versions);
+ callback();
+ },
+ error: function (jqXHR, status, error) {
+ $this.linkeditor.hasChanged();
+ $this.linkeditor.notification(TRANSLATIONS.error_save + ' : ' + error, 'error');
+ },
+ });
+
+ $this.linkeditor.links.loadFontSize();
+ },
+
+ automaticSave: function () {
+ this.save(TRANSLATIONS.automatic_save_message);
+ },
+};
+
+export default MarkdowneditorSave;
--- /dev/null
+function MarkdowneditorUndo(markdowneditor) {
+ this.markdowneditor = markdowneditor;
+ this.ignoreStatesChanges = false;
+ this.states = [];
+ this.indexes = [];
+ this.init();
+}
+
+MarkdowneditorUndo.prototype = {
+ init: function () {
+ },
+
+ initState: function () {
+ if (this.states[this.markdowneditor.getCurrentPage()] === undefined || this.states[this.markdowneditor.getCurrentPage()] === null) {
+ this.indexes[this.markdowneditor.getCurrentPage()] = 0;
+ this.pushState();
+ }
+ },
+
+ _states: function () {
+ let redo = false;
+ let undo = false;
+ let nb = this.states[this.markdowneditor.getCurrentPage()].length;
+ let idx = this.indexes[this.markdowneditor.getCurrentPage()];
+ if (nb > 1) {
+ if (idx < nb) {
+ redo = true;
+ }
+ if (idx > 1) {
+ undo = true;
+ }
+ }
+ return {redo: redo, undo: undo, index: idx, nb: nb};
+ },
+
+ updateIconsStates: function () {
+ let s = this._states();
+ if (s.redo) {
+ $('[data-icon=redo]').removeClass('disabled');
+ } else {
+ $('[data-icon=redo]').addClass('disabled');
+ }
+
+ if (s.undo) {
+ $('[data-icon=undo]').removeClass('disabled');
+ } else {
+ $('[data-icon=undo]').addClass('disabled');
+ }
+ },
+
+ canRedo: function () {
+ return this._states().redo;
+ },
+
+ canUndo: function () {
+ return this._states().undo;
+ },
+
+
+ pushState: function () {
+ if (this.ignoreStatesChanges) {
+ console.log('ignore states changes');
+ return;
+ }
+
+ let index = this.indexes[this.markdowneditor.getCurrentPage()];
+ if (index === 0) {
+ this.states[this.markdowneditor.getCurrentPage()] = [
+ this.markdowneditor.contentMarkdown
+ ];
+ console.log('ok',this.states,this.markdowneditor.editor.getMarkdown(),'ok')
+ }
+
+ let cs = this.markdowneditor.editor.getMarkdown();
+ let ps = this.states[this.markdowneditor.getCurrentPage()][index - 1];
+ if (ps == cs) {
+ console.log('skipped : no change');
+ return;
+ }
+
+ if (index > 0 && index < this.states[this.markdowneditor.getCurrentPage()].length) {
+ this.states[this.markdowneditor.getCurrentPage()] = this.states[this.markdowneditor.getCurrentPage()].slice(0, index);
+ }
+ this.states[this.markdowneditor.getCurrentPage()].push(cs);
+ this.indexes[this.markdowneditor.getCurrentPage()]++;
+
+ //console.log('push current index', index, 'states length', this.states[this.markdowneditor.getCurrentPage()].length);
+
+ this.updateIconsStates();
+ },
+
+ undo: function () {
+ if (!this.canUndo()) {
+ return;
+ }
+ let index = this.indexes[this.markdowneditor.getCurrentPage()];
+ index--;
+ let state = this.states[this.markdowneditor.getCurrentPage()][index - 1];
+ this.ignoreStatesChanges = true;
+ this.markdowneditor.setCurrentState(state);
+ var $this = this;
+ setTimeout(function () {
+ $this.ignoreStatesChanges = false;
+ }, 500);
+ this.indexes[this.markdowneditor.getCurrentPage()] = index;
+
+ //console.log('undo : current index', index, 'states length', this.states[this.markdowneditor.getCurrentPage()].length);
+
+ this.updateIconsStates();
+ },
+
+ redo: function () {
+ if (!this.canRedo()) {
+ return;
+ }
+ let index = this.indexes[this.markdowneditor.getCurrentPage()];
+ let state = this.states[this.markdowneditor.getCurrentPage()][index];
+ this.ignoreStatesChanges = true;
+ this.markdowneditor.setCurrentState(state);
+ var $this = this;
+ setTimeout(function () {
+ $this.ignoreStatesChanges = false;
+ }, 500);
+ index++;
+ this.indexes[this.markdowneditor.getCurrentPage()] = index;
+ //console.log('redo : current index', index, 'states length', this.states[this.markdowneditor.getCurrentPage()].length);
+
+ this.updateIconsStates();
+ }
+}
+
+
+export default MarkdowneditorUndo;
$fbdata['settings']['pages']=$fbdata['pages']=$fluidbook->getPagesNumber();
$fbdata['settings']['imageFormat']=$fluidbook->getImageFormat();
$fbdata['page_dimensions']=[];
+
+ $collection = collect($files);
+ $filesdata = $collection->flatMap(function($item) {
+ $filename = $item->getFilename();
+ return [$filename => file_get_contents($item)];
+ } );
+ $sorted = $filesdata->sortKeys();
@endphp
@extends('layouts.markdowneditor')
</div>
@endsection
-@push('markdown_styles')
- <link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" />
- <link rel="stylesheet"
- href="/packages/markdowneditor/css/style.css?v={{filemtime(public_path('packages/markdowneditor/css/style.css'))}}"/>
-@endpush
@push('markdown_scripts')
<script>
var FLUIDBOOK_DATA = @json($fbdata);
+ var MARKDOWN_DATA = {}
+ @foreach($filesdata as $key => $data)
+ @if(strstr($key,".md"))
+ MARKDOWN_DATA["{{explode('.',$key)[0]}}"] = `{!! $data !!}`;
+ console.log(MARKDOWN_DATA)
+ @endif
+ @endforeach
</script>
<script
src="/packages/markdowneditor/js/markdowneditor.js?v={{filemtime(public_path('packages/markdowneditor/js/markdowneditor.js'))}}"></script>
</script>
@endpush
+@push('markdown_styles')
+ <link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" />
+ <link rel="stylesheet"
+ href="/packages/markdowneditor/css/style.css?v={{filemtime(public_path('packages/markdowneditor/css/style.css'))}}"/>
+@endpush