]> _ Git - fluidbook-toolbox.git/commitdiff
wip #4628 @6
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Fri, 22 Jul 2022 16:48:57 +0000 (18:48 +0200)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Fri, 22 Jul 2022 16:48:57 +0000 (18:48 +0200)
app/Http/Controllers/Admin/Operations/FluidbookPublication/CompositionOperation.php
app/Jobs/FluidbookDocumentUpload.php
app/Models/FluidbookDocument.php
composer.lock
resources/views/fields/fluidbook_composition.blade.php

index 64c6c0daf8250f4113942b7c6db14e7bc7f45343..192aa738f3a7ec4bdeba7f0a9511d42a79ea2d73 100644 (file)
@@ -5,7 +5,6 @@ namespace App\Http\Controllers\Admin\Operations\FluidbookPublication;
 use App\Jobs\FluidbookDocumentUpload;
 use App\Models\FluidbookDocument;
 use Cubist\Backpack\Http\Controllers\Base\XSendFileController;
-use Cubist\Util\Crypt;
 use Cubist\Util\Files\Files;
 use Cubist\Util\Str;
 use Illuminate\Support\Facades\Route;
@@ -19,6 +18,7 @@ trait CompositionOperation
         Route::match(['get'], $segment . '/docs/{doc_id}/thumb_{doc_page}.jpg', $controller . '@getThumb');
         Route::match(['post'], $segment . '/uploaddocument', $controller . '@upload');
         Route::match(['get'], $segment . '/uploadProgress/{uploadID}', $controller . '@uploadProgress');
+        Route::match(['get'], $segment . '/docInfos/{doc_id}', $controller . '@docInfos');
     }
 
     protected function setupCompositionDefaults()
@@ -31,6 +31,15 @@ trait CompositionOperation
         /** @var FluidbookDocument $doc */
         $doc = FluidbookDocument::find($doc_id);
         $path = $doc->getFile($doc_page, 'jpg', 'thumb', true, true, '');
+        if (filesize($path) === 0) {
+            for ($i = 1; $i <= 8; $i++) {
+                clearstatcache();
+                if (filesize($path) > 0) {
+                    break;
+                }
+                sleep($i);
+            }
+        }
         return XSendFileController::sendfile($path);
     }
 
@@ -48,7 +57,13 @@ trait CompositionOperation
         FluidbookDocumentUpload::updateProgression($uploadID, __('Mise en file d\'attente du traitement du document'), 1.2);
 
         FluidbookDocumentUpload::dispatch($uploadID, $document, backpack_user());
-        return response()->json(['uploadID' => $uploadID]);
+        return response()->json(['uploadID' => $uploadID, 'document' => $document->id]);
+    }
+
+    protected function docInfos($doc_id)
+    {
+        $doc = FluidbookDocument::find($doc_id);
+        return response()->json(['pages' => $doc->pages, "size" => $doc->pdf_data['size'], 'numbers' => isset($doc->pdf_data['pagenumbers']) ?: range(1, $doc->pages)]);
     }
 
     protected function uploadProgress($uploadID)
index f2d368c2c9b7ce453d84076b8467e52abd002c84..5aea092aa1ee34333af454a8cf7cedabfebe451a 100644 (file)
@@ -31,10 +31,8 @@ class FluidbookDocumentUpload extends Base
 
     public function handle()
     {
-
         FluidbookDocumentUpload::updateProgression($this->uploadID, __('Début du traitement du document'), 1.25);
         $this->document->processUpload($this->uploadID, $this->isSync());
-
     }
 
     public static function updateProgression($id, $message, $progress)
index cce846fbbdbad48e518b52e47894a4440a7057d0..f95777fa7df0d4e2939c449516bacab2d59acfb5 100644 (file)
@@ -20,7 +20,6 @@ class FluidbookDocument extends ToolboxModel
         'singular' => 'document',
         'plural' => 'documents'];
     protected static $_permissionBase = 'fluidbook-document';
-    protected $_filesData = null;
     protected $casts = ['bookmarks' => 'array', 'pdf_data' => 'array', 'file_data' => 'array'];
 
     public function setFields()
@@ -33,7 +32,6 @@ class FluidbookDocument extends ToolboxModel
         $this->addField('bookmarks', Textarea::class, ['cast' => 'array']);
         $this->addField('pdf_data', Textarea::class, ['cast' => 'array']);
         $this->addField('file_data', Textarea::class, ['cast' => 'array']);
-        $this->addField('pagesnumbers', Text::class);
     }
 
     public function getResolutionRatio()
@@ -47,49 +45,77 @@ class FluidbookDocument extends ToolboxModel
 
     public function processUpload($uploadID, $sync = false)
     {
-        FluidbookDocumentUpload::updateProgression($uploadID, __('Analyse du document'), 1.3);
+        FluidbookDocumentUpload::updateProgression($uploadID, __('Analyse du document'), 1.1);
         $this->checkInfos();
-        FluidbookDocumentUpload::updateProgression($uploadID, __('Nettoyage du document'), 1.5);
+        FluidbookDocumentUpload::updateProgression($uploadID, __('Nettoyage du document'), 1.2);
         $this->fixPDF();
-        FluidbookDocumentUpload::updateProgression($uploadID, __('Découpe du document'), 1.8);
+        FluidbookDocumentUpload::updateProgression($uploadID, __('Découpe du document'), 1.3);
         $this->splitPDF();
-        FluidbookDocumentUpload::updateProgression($uploadID, __('Conversion des pages (:done/:pages)', ['pages' => $this->pages, 'done' => 0]), 2);
+        FluidbookDocumentUpload::updateProgression($uploadID, __('Extraction des textes'), 1.75);
+        $this->extractTexts();
+        FluidbookDocumentUpload::updateProgression($uploadID, __('Extraction des liens'), 1.9);
+        $this->extractLinks();
+        FluidbookDocumentUpload::updateProgression($uploadID, __('Conversion des pages'), 2);
         $jobs = [];
 
         $files = [['jpg', 'thumb'], ['jpg', 150]];
-
+        $nbfiles = count($files);
+        $delay = 0;
         for ($i = 1; $i <= $this->pages; $i++) {
             foreach ($files as $file) {
                 $job = new FluidbookDocumentFileProcess($this, $i, $file[0], $file[1]);
                 if ($sync) {
                     dispatch_sync($job);
                 } else {
-                    dispatch($job);
+                    dispatch($job)->delay($delay);
                 }
                 $jobs[] = $job;
+                if ($i % 20 === 0) {
+                    $delay++;
+                }
+                $this->_checkJobs($uploadID, $jobs, $nbfiles);
             }
         }
 
-        $nbjobs = count($jobs);
-        $nbfiles = count($files);
-
         while (true) {
-            $done = 0;
-            foreach ($jobs as $job) {
-                /** @var $job FluidbookDocumentFileProcess */
-                if ($job->isDone()) {
-                    $done++;
-                }
-            }
-            $progress = $done / $nbjobs;
-            FluidbookDocumentUpload::updateProgression($uploadID, __('Conversion des pages (:done/:pages)', ['pages' => $this->pages, 'done' => round($done / $nbfiles)]), 2 + $progress);
-            if ($progress === 1) {
-                break;
+            if ($this->_checkJobs($uploadID, $jobs, $nbfiles) === 1) {
+                return;
             }
             usleep(0.25 * 1000000);
         }
     }
 
+    public function extractTexts()
+    {
+        PDFTools::extractTexts($this->path('original.pdf'), $this->path(), '', false, true);
+        PDFTools::extractHighlightsData($this->path('original.pdf'), $this->path());
+    }
+
+    public function extractLinks()
+    {
+        PDFTools::extractLinks($this->path('original.pdf'), $this->path());
+    }
+
+    protected function _checkJobs($uploadID, $jobs, $nbfiles)
+    {
+        $nbjobs = $nbfiles * $this->pages;
+
+        $done = 0;
+        foreach ($jobs as $job) {
+            /** @var $job FluidbookDocumentFileProcess */
+            if ($job->isDone()) {
+                $done++;
+            }
+        }
+        $progress = $done / $nbjobs;
+        if ($progress === 1) {
+            FluidbookDocumentUpload::updateProgression($uploadID, __('Conversion terminée'), 3);
+        } else {
+            FluidbookDocumentUpload::updateProgression($uploadID, __('Conversion des pages (:done/:pages)', ['pages' => $this->pages, 'done' => round($done / $nbfiles)]), 2 + $progress);
+        }
+        return $progress;
+    }
+
     public function getMobileFirstRatio()
     {
         $this->checkInfos();
@@ -103,7 +129,6 @@ class FluidbookDocument extends ToolboxModel
             $this->pages = $infos['pages'];
             $this->pdf_data = $infos['infos'];
             $this->bookmarks = $infos['bookmarks'];
-            $this->pagesnumbers = $infos['numberSections'];
             $this->saveWithoutFlushingCache();
         }
     }
@@ -128,7 +153,11 @@ class FluidbookDocument extends ToolboxModel
      */
     public function path($path = ''): string
     {
-        return rtrim(self::WS_DOCS . $this->id . ($path ? DIRECTORY_SEPARATOR . ltrim($path, DIRECTORY_SEPARATOR) : $path), DIRECTORY_SEPARATOR);
+        $res = rtrim(self::WS_DOCS . $this->id . ($path ? DIRECTORY_SEPARATOR . ltrim($path, DIRECTORY_SEPARATOR) : $path), DIRECTORY_SEPARATOR);
+        if (!$path) {
+            $res .= DIRECTORY_SEPARATOR;
+        }
+        return $res;
     }
 
     public function hasFile($page, $format = 'jpg', $resolution = 150, $withText = true, $withGraphics = true, $version = 'html')
@@ -147,6 +176,9 @@ class FluidbookDocument extends ToolboxModel
             if (filesize($path) < $minsize) {
                 return false;
             }
+            if (file_exists($path . '.lock')) {
+                return false;
+            }
             if ($format === 'svg') {
                 $reffile = $this->path('/html/fp' . $page . '.svg');
                 if (!file_exists($reffile) || filemtime($path) < filemtime($reffile)) {
index 954a9e5e08506fee6d44a96da5bb333d19bfcfa6..f65d05dc12c69a1fcd474605641526083e81168a 100644 (file)
             "source": {
                 "type": "git",
                 "url": "git://git.cubedesigners.com/cubist_cms-back.git",
-                "reference": "5037fafa790b4d6a0157f38f7237c45aa69bf157"
+                "reference": "f2cddfa7b1a8446ba3430147ec045dd4777a8658"
             },
             "dist": {
                 "type": "tar",
-                "url": "https://composer.cubedesigners.com/dist/cubist/cms-back/cubist-cms-back-dev-master-bc5679.tar",
-                "reference": "5037fafa790b4d6a0157f38f7237c45aa69bf157",
-                "shasum": "0bccb1ee64d0f71da2e451ced0a4c329decbe0ec"
+                "url": "https://composer.cubedesigners.com/dist/cubist/cms-back/cubist-cms-back-dev-master-4b1d60.tar",
+                "reference": "f2cddfa7b1a8446ba3430147ec045dd4777a8658",
+                "shasum": "e2470e1897d0463adc15af5c713ccfbde756bcf2"
             },
             "require": {
                 "backpack/backupmanager": "^3.0",
                 }
             ],
             "description": "Cubist Backpack extension",
-            "time": "2022-07-19T13:22:56+00:00"
+            "time": "2022-07-21T18:23:21+00:00"
         },
         {
             "name": "cubist/cms-front",
             "source": {
                 "type": "git",
                 "url": "git://git.cubedesigners.com/cubist_pdf.git",
-                "reference": "dfbda143ad4963784a2251af488978d92da79d51"
+                "reference": "b93a3841c212ca8bf9793da611d90497b4f9a6de"
             },
             "dist": {
                 "type": "tar",
-                "url": "https://composer.cubedesigners.com/dist/cubist/pdf/cubist-pdf-dev-master-1ba061.tar",
-                "reference": "dfbda143ad4963784a2251af488978d92da79d51",
-                "shasum": "1fd430d15409cfcc232ded890019e8dcebf061db"
+                "url": "https://composer.cubedesigners.com/dist/cubist/pdf/cubist-pdf-dev-master-876ad1.tar",
+                "reference": "b93a3841c212ca8bf9793da611d90497b4f9a6de",
+                "shasum": "7c956335d1f230f7f7bd313e72dd04115f2fea1f"
             },
             "require": {
                 "cubist/util": "dev-master",
                 "cubist",
                 "pdf"
             ],
-            "time": "2022-07-13T16:13:36+00:00"
+            "time": "2022-07-21T18:23:40+00:00"
         },
         {
             "name": "cubist/scorm",
         },
         {
             "name": "laravel/framework",
-            "version": "v8.83.20",
+            "version": "v8.83.21",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/framework.git",
-                "reference": "aa5908e83fccb18b135ca31aa0342cf4bd6909a8"
+                "reference": "1b3b06e5f419eef9bc3dfa06376dd60f5de524bc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/framework/zipball/aa5908e83fccb18b135ca31aa0342cf4bd6909a8",
-                "reference": "aa5908e83fccb18b135ca31aa0342cf4bd6909a8",
+                "url": "https://api.github.com/repos/laravel/framework/zipball/1b3b06e5f419eef9bc3dfa06376dd60f5de524bc",
+                "reference": "1b3b06e5f419eef9bc3dfa06376dd60f5de524bc",
                 "shasum": ""
             },
             "require": {
                 "issues": "https://github.com/laravel/framework/issues",
                 "source": "https://github.com/laravel/framework"
             },
-            "time": "2022-07-19T14:11:02+00:00"
+            "time": "2022-07-21T19:36:48+00:00"
         },
         {
             "name": "laravel/serializable-closure",
index fbbbe3050613c1161e83fdb836915715192e7229..6fcd987b6c525b8e96c602fcff60608a19f11bc9 100644 (file)
@@ -3,10 +3,10 @@
     @push('crud_fields_scripts')
         <script>
             $(function () {
-                var conversion = '';
                 var conversionOperation;
                 var conversionPages;
-                var progressInterval;
+                var conversionDocument;
+                var selected = [];
 
                 function initPages() {
                     var data = JSON.parse($("#compositionField").val());
 
 
                     $.each(data, function (pageNr, page) {
-                        addPage(page[0], page[1], numbers[pageNr - 1], sizes[page[0]]);
+                        var size = sizes[page[0]];
+                        if (size === undefined) {
+                            size = [210, 297]
+                        }
+                        addPage(page[0], page[1], numbers[pageNr - 1], size);
                     });
 
                     var composition = $('#composition_pages').get(0);
                         handle: '.handle',
                         onSort: function (e) {
                             updateComposition();
+                        },
+                        onSelect: function (e) {
+                            $(".pdfselected").removeClass('pdfselected');
+                            selected = e.items;
                         }
                     });
 
@@ -45,7 +53,6 @@
                         $("#pagenumber_input").remove();
 
                         if (v !== $(this).attr('data-orig-value')) {
-                            console.log('change', v, $(this).data('orig-value'));
                             updateNumFromEdit(v, p);
                         }
 
                     $(document).on('change', '#compositionUploadBrowse', function () {
                         $("#compositionUploadForm").submit();
                     });
+
                     $(document).on('submit', '#compositionUploadForm', function () {
                         $(this).ajaxSubmit({
                             success: function (data) {
                                 var uploadID = data.uploadID;
-                                progressInterval = setInterval(function () {
-                                    updateProgressBar(uploadID);
-                                }, 250);
+                                conversionDocument = data.document;
+                                updateProgressBar(uploadID);
                             },
                             uploadProgress: function (event, position, total, percentComplete) {
                                 var progress = position / total;
                                 var message = '{{__('Chargement du document')}}';
                                 if (progress === 1) {
                                     message = '{{__('Initialisation de la conversion')}}';
+                                    progress = 1.05;
                                 }
                                 showProgressBar(message, progress);
                             },
                                     type: 'error',
                                     text: '{{__('Une erreur s\'est produite lors du chargement du document')}}',
                                 }).show();
-                                conversion = '';
+                                hideProgressBar();
                             }
                         });
                         return false;
                     $.ajax({
                         url: '{{backpack_url($entry->getOption('name').'/uploadProgress')}}' + '/' + uploadID,
                         success: function (data) {
-                            showProgressBar(data.message, data.progress);
+                            showProgressBar(data.message, parseFloat(data.progress), uploadID);
                         }
-                    })
+                    });
                 }
 
-                function showProgressBar(message, progress) {
-                    console.log(message, progress);
+                function showProgressBar(message, progress, uploadID) {
                     if ($("#compositionProgress").length === 0) {
-                        $('body').append('<div id="compositionProgress"><div><span></span><progress max="100"></progress></div></div>');
+                        $('body').append('<div id="compositionProgress"><div><span></span><progress data-progress="" data-step="0" value="0" max="100"></progress></div></div>');
                     }
-                    var p = Math.round((progress % 1) * 100);
-
-                    var step = Math.floor(progress);
-
-                    $("#compositionProgress progress").attr('data-step', step).attr('value', p).text(p + '%');
-                    $("#compositionProgress span").text(message);
+                    if (message !== '' && progress > 0) {
+                        $("#compositionProgress span").text(message);
+                        if ($("#compositionProgress progress").attr('data-progress') == progress) {
+                            return;
+                        }
+                        var dp = (progress % 1);
+                        if (dp === 0 && progress > 0) {
+                            dp = 1;
+                        }
+                        var p = Math.round(dp * 100);
+                        var step = progress - dp;
+                        var duration = 0.5;
+                        if (p < $("#compositionProgress progress").attr('value')) {
+                            duration = 0;
+                        }
 
+                        gsap.to($("#compositionProgress progress"), {
+                            duration: duration, ease: 'none', attr: {'value': p}, onComplete: function () {
+                                $("#compositionProgress progress").attr('data-step', step);
+                            }
+                        });
+                    }
 
-                    if (progress === 3) {
+                    if (progress >= 3) {
                         hideProgressBar();
+                        endConversion();
+                    } else if (uploadID !== undefined) {
+                        setTimeout(function () {
+                            updateProgressBar(uploadID);
+                        }, 250);
                     }
                 }
 
+                function endConversion() {
+                    $.ajax({
+                        url: '{{backpack_url($entry->getOption('name').'/docInfos')}}' + '/' + conversionDocument,
+                        success: function (data) {
+                            putDocumentInComposition(conversionDocument, data.pages, data.numbers, data.size, conversionOperation, conversionPages);
+                        }
+                    });
+                }
+
                 function hideProgressBar() {
-                    clearInterval(progressInterval);
-                    console.log('End conversion');
-                    $("#compositionProgress").remove();
+                    setTimeout(function () {
+                        $("#compositionProgress").remove();
+                    }, 2000);
                 }
 
                 function updateComposition() {
                     });
                 }
 
-
                 function compositionDeselectAll() {
                     $(".page").each(function () {
                         Sortable.utils.deselect(this);
                     $("#composition_pages .page.selected").each(function () {
                         compositionDeletePage(this);
                     });
+                    updateComposition();
                 }
 
                 function compositionDeletePage(page) {
                     return $("#composition_pages .page.selected").length > 0;
                 }
 
-                function addPage(document_id, document_page, pageNumber, size) {
-                    $("#composition_pages").append('<div class="page" data-id="[' + document_id + ',' + document_page + ']"><div class="handle"><img width="' + size[0] + '" height="' + size[1] + '" src="/fluidbook-publication/docs/' + document_id + '/thumb_' + document_page + '.jpg" /></div><span>' + pageNumber + '</span></div>');
+                function addPage(document_id, document_page, pageNumber, size, selector, operation) {
+                    if (selector === undefined) {
+                        selector = "#composition_pages";
+                    }
+                    if (operation === undefined) {
+                        operation = 'append';
+                    }
+                    $(selector)[operation](getPage(document_id, document_page, pageNumber, size));
                 }
 
-                function compositionBrowse(operation, pages) {
-                    if (conversion !== '') {
-                        new Noty({
-                            type: 'warning',
-                            text: '{{__("Un document est déjà en cours d'ajout")}}',
-                        }).show();
-                        return;
+                function getPage(document_id, document_page, pageNumber, size) {
+                    return '<div class="page" data-id="[' + document_id + ',' + document_page + ']"><div class="handle"><img width="' + size[0] + '" height="' + size[1] + '" src="/fluidbook-publication/docs/' + document_id + '/thumb_' + document_page + '.jpg" /></div><span>' + pageNumber + '</span></div>';
+                }
+
+                function addPages(pages, selector, operation) {
+                    var p = '';
+                    $.each(pages, function (k, v) {
+                        p += getPage(v.document_id, v.document_page, v.pageNumber, v.size);
+                    });
+                    if (selector === undefined) {
+                        selector = "#composition_pages";
+                    }
+                    if (operation === undefined) {
+                        operation = 'append';
                     }
+                    $(selector)[operation](p);
+                }
+
+                function compositionBrowse(operation, pages) {
                     conversionOperation = operation;
                     conversionPages = pages;
 
                         '<input type="file" id="compositionUploadBrowse" name="file" value="" accept=".pdf" />' +
                         '<input type="hidden" name="_token" value="{{csrf_token()}}" />' +
                         '</form>');
-                    $('body').append(form);
-
+                    $('#composition_pages').append(form);
                     $("#compositionUploadBrowse").click();
                 }
 
                         deleteSelection: {
                             name: "{{__('Supprimer la selection')}}",
                             callback: function (key, opt, e) {
+                                $.each(selected, function (k, v) {
+                                    $(v).addClass('selected');
+                                });
                                 compositionDeleteSelection();
                             },
                         },
                         replaceSelection: {
                             name: "{{__('Remplacer les pages de la sélection')}}",
                             callback: function (key, opt) {
+                                var selection = [];
+                                $.each(selected, function (k, v) {
+                                    $(v).addClass('selected');
+                                });
+                                $('#composition_pages .page.selected').each(function () {
+                                    $(this).removeClass('selected').addClass('pdfselected');
+                                    selection.push($(this).index() + 1);
+                                });
                                 compositionBrowse('replace', selection);
                             }
                         },
                         insertBefore: {
                             name: "{{__('Insérer des pages avant cette page')}}",
                             callback: function (key, opt) {
-                                compositionBrowse('before', opt.$trigger[0].index() + 1);
+                                compositionBrowse('before', $(opt.$trigger[0]).index() + 1);
+                                $(opt.$trigger[0]).addClass('pdfselected');
                             }
                         },
                         insertAfter: {
                             name: "{{__('Insérer des pages après cette page')}}",
                             callback: function (key, opt) {
-                                compositionBrowse('before', opt.$trigger[0].index() + 1);
+                                compositionBrowse('after', $(opt.$trigger[0]).index() + 1);
+                                $(opt.$trigger[0]).addClass('pdfselected');
                             }
                         },
                         replacePage: {
                             name: "{{__('Remplacer cette page')}}",
                             callback: function (key, opt) {
-                                compositionBrowse('replace', [opt.$trigger[0].index() + 1]);
+                                compositionBrowse('replace', [$(opt.$trigger[0]).index() + 1]);
+                                $(opt.$trigger[0]).addClass('pdfselected');
                             }
                         },
                         sep3: "---------",
                         from = $(page).index() + 1;
                     }
 
-                    var j = start;
-                    var pages = getPageNumber();
-                    for (var i = from; i <= pages; i++) {
-                        var n = prefix + separator + getNumByType(j, type);
+                    if (type === 'free') {
+                        $("#composition_pages .page").eq(from - 1).find('span').text(start);
+                    } else {
+                        var j = start;
+                        var pages = getPageNumber();
+                        for (var i = from; i <= pages; i++) {
+                            var n = prefix + separator + getNumByType(j, type);
 
-                        $("#composition_pages .page").eq(i - 1).find('span').text(n);
-                        j++;
+                            $("#composition_pages .page").eq(i - 1).find('span').text(n);
+                            j++;
+                        }
                     }
                     updateComposition();
                 }
                     var type;
                     var start;
                     var prefix = '';
+                    var origv = v;
                     if (v.indexOf('.') != -1) {
                         separator = '.';
                     } else if (v.indexOf(' ') != -1) {
                         type = 'decnum';
                         start = parseInt(v);
                     } else {
-                        return;
+                        type = 'free';
+                        start = origv;
                     }
                     updateNum(type, p, start, prefix, separator);
                 }
                     return roman;
                 }
 
+                function putDocumentInComposition(doc, pages, numbers, size, operation, place) {
+                    if (operation === 'replace') {
+                        if (pages === place.length) {
+                            // Keep page numbers if selection has the same size as the new pdf
+                            $.each(place, function (k, p) {
+                                numbers[k] = $('#composition_pages .page:eq(' + (p - 1) + ') span').text();
+                            });
+                        }
+                        $(".pdfselected").each(function () {
+                            compositionDeletePage($(this));
+                        });
+                        operation = 'after';
+                        place = place[0] - 1;
+                    }
+                    place = Math.min(getPageNumber(), Math.max(1, place));
+                    if (operation === 'after' || operation === 'before') {
+                        var list = [];
+                        for (var i = 1; i <= pages; i++) {
+                            list.push({document_id: doc, document_page: i, pageNumber: numbers[i - 1], size});
+                        }
+                        var selector;
+                        if (getPageNumber() === 0) {
+                            operation = 'append';
+                            selector = '#composition_pages';
+                        } else {
+                            selector = '#composition_pages .page:eq(' + (place - 1) + ')';
+                        }
+                        addPages(list, selector, operation);
+                    }
+                    updateComposition();
+                    $(".pdfselected").removeClass('pdfselected');
+                }
+
                 initPages();
             });
         </script>
         <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.2/jquery.ui.position.min.js"
                 integrity="sha512-878jmOO2JNhN+hi1+jVWRBv1yNB7sVFanp2gA1bG++XFKNj4camtC1IyNi/VQEhM2tIbne9tpXD4xaPC4i4Wtg=="
                 crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js"></script>
     @endpush
 
     @push('crud_fields_styles')
             }
 
             #composition_pages .page:hover, #composition_pages .page.selected {
-                border-color: #467fcf;
+                border-color: #467fcf !important;
             }
 
+            #composition_pages .page.pdfselected {
+                border-color: #0ba234;
+                background-color: #7dde98;
+            }
+
+
             #composition_pages .page.selected {
-                background-color: #b5cbf5;
+                background-color: #b5cbf5 !important;
             }
 
             #composition_pages .page .handle {
 
             #compositionProgress div {
                 position: absolute;
-                top: 50%;
-                left: 50%;
-                width: 20%;
+                top: calc(50% - 65px);
+                left: calc(50% - 200px);
+                width: 400px;
+                height: 130px;
                 padding: 20px;
                 background-color: #fff;
+                border-radius: 4px;
+            }
+
+            #compositionProgress span {
+                display: block;
+                text-align: center;
+                font-size: 17px;
+            }
+
+            #compositionProgress progress {
+                width: 100%;
+                margin: 10px auto;
+                height: 25px;
+                appearance: none;
+                border-radius: 2px;
+                border: 1px solid rgba(0, 40, 100, .12);
+            }
+
+            #compositionProgress progress::-moz-progress-bar, #compositionProgress progress::-webkit-progress-value {
+                border-radius: 2px;
+            }
+
+            #compositionProgress progress[data-step="0"] {
+                background-color: #fff;
+            }
+
+            #compositionProgress progress[data-step="0"]::-moz-progress-bar, #compositionProgress progress[data-step="0"]::-webkit-progress-value {
+                background-color: #3d86ee;
+            }
+
+            #compositionProgress progress[data-step="1"] {
+                background-color: #3d86ee;
+            }
+
+            #compositionProgress progress[data-step="1"]::-moz-progress-bar, #compositionProgress progress[data-step="1"]::-webkit-progress-value {
+                background-color: #3471c8;
+            }
+
+            #compositionProgress progress[data-step="2"] {
+                background-color: #3471c8;
+            }
+
+            #compositionProgress progress[data-step="2"]::-moz-progress-bar, #compositionProgress progress[data-step="2"]::-webkit-progress-value {
+                background-color: #20457b;
+            }
+
+            .pace {
+                opacity: 0;
+            }
+
+            #compositionUploadForm {
+                opacity: 0;
+                position: absolute;
+                top: 0;
+                left: 0;
             }
         </style>