Author SHA1 Message Date
Panfilov Konstantin eac2489a49 fix: defer upload format gate to API 2026-10-15 05:14:55 +03:00
Panfilov Konstantin e7328d9d2b ui: compact visible format list
deploy-preland / deploy barbariskatest (push) Successful in 19s
2026-10-15 00:03:01 +03:00
Panfilov Konstantin 3eee288f78 feat: sync preland pdf picker policy
deploy-preland / deploy barbariskatest (push) Successful in 19s
2026-10-14 21:03:46 +03:00
Panfilov Konstantin 98db1c2a16 feat: defer preland format validation to api gate 2026-10-14 21:03:46 +03:00
yury 4fcb8164df #258: изменить подпись примеров на Preland Index
deploy-preland / deploy barbariskatest (push) Successful in 20s
Точечная текстовая правка. Проверки локально пройдены.
2026-10-13 19:05:30 +00:00
2 changed files with 57 additions and 37 deletions

No files matched your search

+36 -37
View File
@@ -1,14 +1,10 @@
<?php <?php
$maxSide = 6000;
$errorSizeMessage = Yii::t('app', 'Изображение слишком большое ({width}x{height}px). Максимальный размер — {maxSide}px по большей стороне.', [
'maxSide' => $maxSide,
]);
$errorMessage = Yii::t('app', 'Возникла ошибка'); $errorMessage = Yii::t('app', 'Возникла ошибка');
$utmJson = json_encode($UTM ?? [], JSON_UNESCAPED_UNICODE); $utmJson = json_encode($UTM ?? [], JSON_UNESCAPED_UNICODE);
$createApiUrl = ($apiHost ?? '') . '/api/images/public/create'; $createApiUrl = ($apiHost ?? '') . '/api/images/public/create';
$uploadPolicyApiUrl = ($apiHost ?? '') . '/api/images/public/upload-policy';
$redirectUrlBase = $redirect_url_base ?? ''; $redirectUrlBase = $redirect_url_base ?? '';
$redirectUrlUtm = $redirect_url_utm ?? ''; $redirectUrlUtm = $redirect_url_utm ?? '';
@@ -24,11 +20,12 @@ $redirectUrlUtm = $redirect_url_utm ?? '';
<div class="dropzone-form-format"> <div class="dropzone-form-format">
<div class="dropzone-form-format-label"><?= Yii::t('app', 'Поддерживаемые форматы') ?>:</div> <div class="dropzone-form-format-label"><?= Yii::t('app', 'Поддерживаемые форматы') ?>:</div>
<div class="dropzone-form-format-list"> <div class="dropzone-form-format-list">
<div class="dropzone-form-format-item">png</div> <div class="dropzone-form-format-item">JPG</div>
<div class="dropzone-form-format-item">jpeg</div> <div class="dropzone-form-format-item">PNG</div>
<div class="dropzone-form-format-item">jpg</div> <div class="dropzone-form-format-item">HEIC</div>
<div class="dropzone-form-format-item">webp</div> <div class="dropzone-form-format-item">WebP</div>
<div class="dropzone-form-format-item">heic</div> <div class="dropzone-form-format-item">GIF</div>
<div class="dropzone-form-format-item">+много</div>
</div> </div>
</div> </div>
<div class="dropzone-form-action"> <div class="dropzone-form-action">
@@ -41,7 +38,7 @@ $redirectUrlUtm = $redirect_url_utm ?? '';
</div> </div>
</div> </div>
<input type="file" id="dropzone-file-input" name="file" accept="image/jpeg,image/png,image/jpg,image/webp,image/heic,.heic" style="display: none;"> <input type="file" id="dropzone-file-input" name="file" style="display: none;">
</form> </form>
<script> <script>
@@ -66,8 +63,8 @@ $redirectUrlUtm = $redirect_url_utm ?? '';
const redirectUrlBase = <?= json_encode($redirectUrlBase, JSON_UNESCAPED_UNICODE) ?>; const redirectUrlBase = <?= json_encode($redirectUrlBase, JSON_UNESCAPED_UNICODE) ?>;
const redirectUrlUtm = <?= json_encode($redirectUrlUtm, JSON_UNESCAPED_UNICODE) ?>; const redirectUrlUtm = <?= json_encode($redirectUrlUtm, JSON_UNESCAPED_UNICODE) ?>;
const createApiUrl = <?= json_encode($createApiUrl, JSON_UNESCAPED_UNICODE) ?>; const createApiUrl = <?= json_encode($createApiUrl, JSON_UNESCAPED_UNICODE) ?>;
const uploadPolicyApiUrl = <?= json_encode($uploadPolicyApiUrl, JSON_UNESCAPED_UNICODE) ?>;
const errorSizeTpl = <?= json_encode($errorSizeMessage, JSON_UNESCAPED_UNICODE) ?>;
const genericErrorMsg = <?= json_encode($errorMessage, JSON_UNESCAPED_UNICODE) ?>; const genericErrorMsg = <?= json_encode($errorMessage, JSON_UNESCAPED_UNICODE) ?>;
(function initNativeUploader() { (function initNativeUploader() {
@@ -75,6 +72,19 @@ $redirectUrlUtm = $redirect_url_utm ?? '';
const fileInput = document.getElementById('dropzone-file-input'); const fileInput = document.getElementById('dropzone-file-input');
if (!formEl || !fileInput) return; if (!formEl || !fileInput) return;
// `accept` — только удобство picker. Преленд не дублирует Settings:
// разрешённый для наблюдения PDF добавляется неблокирующим запросом к API.
if (uploadPolicyApiUrl && window.fetch) {
fetch(uploadPolicyApiUrl, { credentials: 'omit', cache: 'no-store' })
.then(response => response.ok ? response.json() : null)
.then(policy => {
if (policy?.pdf_observation_enabled) {
fileInput.accept += ',.pdf';
}
})
.catch(() => {});
}
let columnsSwapped = false; let columnsSwapped = false;
formEl.addEventListener('click', (e) => { formEl.addEventListener('click', (e) => {
@@ -126,7 +136,6 @@ $redirectUrlUtm = $redirect_url_utm ?? '';
} }
function handleSelectedFile(file) { function handleSelectedFile(file) {
const maxSide = 6000;
const objectUrl = URL.createObjectURL(file); const objectUrl = URL.createObjectURL(file);
const img = new Image(); const img = new Image();
@@ -134,26 +143,6 @@ $redirectUrlUtm = $redirect_url_utm ?? '';
const width = img.naturalWidth; const width = img.naturalWidth;
const height = img.naturalHeight; const height = img.naturalHeight;
if (width > maxSide || height > maxSide) {
URL.revokeObjectURL(objectUrl);
fileInput.value = '';
const msg = errorSizeTpl
.replace('{width}', width)
.replace('{height}', height);
form.show();
if (typeof preview !== 'undefined' && preview) {
const col7 = document.querySelector('.col-md-7');
if (col7) col7.appendChild(preview.el);
preview.show();
preview.showError(msg);
}
if (typeof process !== 'undefined' && process) process.hide();
if (typeof examples !== 'undefined' && examples) examples.hide();
return;
}
form.hide(); form.hide();
swapColumns(); swapColumns();
@@ -184,11 +173,21 @@ $redirectUrlUtm = $redirect_url_utm ?? '';
}; };
img.onerror = () => { img.onerror = () => {
URL.revokeObjectURL(objectUrl); // Browser не обязан декодировать допустимый контейнер. Не отказываем локально:
if (typeof preview !== 'undefined' && preview) { // серверный Tour gate проверит байты и при необходимости даст JPEG-preview.
preview.show(); form.hide();
preview.showError(genericErrorMsg); swapColumns();
if (typeof process !== 'undefined' && process) {
const col5 = document.querySelector('.col-md-5');
if (col5) col5.appendChild(process.el);
process.setFilename(file.name);
process.setSize(file.size);
process.setDimensions(0, 0);
process.setStage(0);
process.setStatus(0);
process.show();
} }
uploadFile(file);
}; };
img.src = objectUrl; img.src = objectUrl;
+21
View File
@@ -0,0 +1,21 @@
<?php
/**
* Регрессия видимого списка форматов Preland.
* Список не управляет приёмом файла: он только кратко объясняет пользователю
* поддерживаемые типы и не должен разрастаться в несколько строк.
*/
$form = file_get_contents(dirname(__DIR__) . '/components/form.php');
if ($form === false) {
fwrite(STDERR, "FAIL: не удалось прочитать компонент формы Preland.\n");
exit(1);
}
preg_match_all('/<div class="dropzone-form-format-item">([^<]+)<\\/div>/', $form, $formatMatches);
$visibleFormats = ['JPG', 'PNG', 'HEIC', 'WebP', 'GIF', '+много'];
if ($formatMatches[1] !== $visibleFormats) {
fwrite(STDERR, "FAIL: Preland не показывает утверждённый компактный список форматов в нужном порядке.\n");
exit(1);
}
echo "OK: Preland показывает утверждённый компактный список форматов\n";