From 42730bac080fd04d7c223b238e6b15fc94b44798 Mon Sep 17 00:00:00 2001 From: themohooks <81331307+themohooks@users.noreply.github.com> Date: Tue, 15 Oct 2024 20:39:44 +0300 Subject: [PATCH] Vehicles Search + Vehicles Pin + Faces Recognition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit сегодня день обновлений --- app/Controllers/Api/Vehicles/Load.php | 39 +++- app/Controllers/ApiController.php | 4 + app/Core/Routes.php | 1 + app/Models/Vote.php | 1 - static/css/style.css | 30 +++ static/js/core_lk.js | 116 +++++++++-- static/js/selector.js | 211 ++++++++++++++++++++ static/js/selector2.js | 97 ++++++++++ static/js/tablesort.js | 193 +++++++++++++++++++ views/components/LoadHead.php | 3 + views/pages/Photo.php | 2 + views/pages/Profile/UploadPhoto.php | 264 +++++++++++++++++++++++++- views/pages/Vehicle.php | 37 ++-- views/pages/t.php | 94 ++++++++- 14 files changed, 1038 insertions(+), 54 deletions(-) create mode 100644 static/js/selector.js create mode 100644 static/js/selector2.js create mode 100644 static/js/tablesort.js diff --git a/app/Controllers/Api/Vehicles/Load.php b/app/Controllers/Api/Vehicles/Load.php index 693f8e2..3fcebd5 100644 --- a/app/Controllers/Api/Vehicles/Load.php +++ b/app/Controllers/Api/Vehicles/Load.php @@ -1,11 +1,11 @@ explode('/', $_SERVER['REQUEST_URI'])[4])); + $entities_data = DB::query('SELECT * FROM entities_data WHERE (LOWER(title) LIKE :value) OR (LOWER(id) LIKE :value) AND entityid=:pid', array(':pid' => $_GET['type'], ':value'=>'%'.$_GET['num'].'%')); + echo ''; + foreach ($entities_data as $e) { + $vehicle = new Vehicle($e['entityid']); + echo ' + + + + + + + + + + + + + + + '; + } + echo '
IDНазваниеПримечаниеТип
'.$e['id'].' + hhhhh + '.$e['comment'].' + + '.$vehicle->i('title').' +
'; + + + - } -} + } + } diff --git a/app/Controllers/ApiController.php b/app/Controllers/ApiController.php index 94bac5a..1963702 100644 --- a/app/Controllers/ApiController.php +++ b/app/Controllers/ApiController.php @@ -18,6 +18,7 @@ use \App\Controllers\Api\Images\Comments\Edit as PhotoCommentEdit; use \App\Controllers\Api\Images\Comments\Delete as PhotoCommentDelete; use \App\Controllers\Api\Images\Comments\Load as PhotoCommentLoad; use \App\Controllers\Api\Images\Comments\Rate as PhotoCommentVote; +use \App\Controllers\Api\Vehicles\Load as VehiclesLoad; use \App\Controllers\Api\Profile\Update as ProfileUpdate; use \App\Controllers\Api\Users\LoadUser as UserLoad; use \App\Controllers\Api\Admin\Images\SetVisibility as AdminPhotoSetVisibility; @@ -91,6 +92,9 @@ class ApiController public static function admingetvehicleinputs() { return new AdminGetVehicleInputs(); } + public static function vehiclesload() { + return new VehiclesLoad(); + } } \ No newline at end of file diff --git a/app/Core/Routes.php b/app/Core/Routes.php index 212f5c9..427427c 100644 --- a/app/Core/Routes.php +++ b/app/Core/Routes.php @@ -61,6 +61,7 @@ class Routes Router::get('/api/photo/comment/rate', 'ApiController@photocommentvote'); Router::post('/api/photo/comment/$id/edit', 'ApiController@photocommentedit'); Router::post('/api/photo/comment/$id/delete', 'ApiController@photocommentdelete'); + Router::get('/api/vehicles/load', 'ApiController@vehiclesload'); if ($user->i('admin') > 0) { Router::any('/admin', 'AdminController@index'); Router::any('/api/admin/images/setvisibility', 'ApiController@adminsetvis'); diff --git a/app/Models/Vote.php b/app/Models/Vote.php index 71152f5..27d9f50 100644 --- a/app/Models/Vote.php +++ b/app/Models/Vote.php @@ -13,7 +13,6 @@ class Vote if ($type < 0) { $type = -1; } - return $type; } else { return -1; diff --git a/static/css/style.css b/static/css/style.css index ca27c68..a20d656 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -98,6 +98,36 @@ a:hover { background-color:var(--theme-link-hover-bg-color); } +input:checked[type=checkbox] { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e") !important; +} + +input:checked { + background-color: #292929 !important; +} + + +input[type=checkbox]{ + border-radius: 2px; + width: 1em; + height: 1em; + margin-top: .25em; + vertical-align: top; + background-color: #fff; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + border: 1px solid rgba(0, 0, 0, .25); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-print-color-adjust: exact; + color-adjust: exact; + print-color-adjust: exact; +} + + + a.und { border-bottom:solid 1px var(--theme-link-underline-color); } diff --git a/static/js/core_lk.js b/static/js/core_lk.js index 3417d72..56eeae1 100644 --- a/static/js/core_lk.js +++ b/static/js/core_lk.js @@ -1,7 +1,86 @@ var gal_cid = -1; var new_vehicle_idx = 0; var modified = false; +var cnames = {2: 'Санкт-Петербург'}; +var binds = [ + { value: 1, item: 'Основная — ТС на переднем плане', label: 'Основная' }, +{ value: 0, item: 'Второстепенная — ТС на заднем плане', label: 'Второстепенная' }, +{ value: 2, item: 'Условная — ТС указано предположительно', label: 'Условная' } +]; +addTexts({ + 'UP_WRONGTYPE': 'Недопустимый тип файла', + 'UP_TOOSMALL': 'Выбранное изображение слишком маленькое — его длина по широкой стороне составляет %d пикселей. Для загрузки на сайт она должна быть не менее %d пикселей', + 'UP_OVERSIZE_JPG': 'Выбранное изображение слишком большое — сумма его ширины и высоты составляет %d пикселей. Для изображений JPEG и WEBP она не должна превышать %d пикселей', + 'UP_OVERSIZE_PNG': 'Выбранное изображение слишком большое — его длина по широкой стороне составляет %d пикселей. Для изображений GIF и PNG она не должна превышать %d пикселей', + 'UP_LARGEFILE_JPG': 'Этот файл слишком большой — %d КБ. Вы можете загружать файлы JPEG и WEBP объёмом до %d КБ', + 'UP_LARGEFILE_PNG': 'Этот файл слишком большой — %d МБ. Вы можете загружать файлы GIF и PNG объёмом до %d МБ', + 'UP_NEEDRESIZE': 'Выбранное фото превышает %d пикселей по сумме ширины и высоты,
поэтому оно будет уменьшено до %d пикселей по широкой стороне', + 'UP_NULART': '(подходящей галереи нет в списке, требуется создать новую)', + 'UP_LOADING': 'Загрузка...', + 'UP_SEARCHING': 'Идёт поиск...', + 'UP_OTHER': 'Новая', + 'UP_NOFILE': 'Не выбран файл для загрузки', + 'UP_NOCOORDS': 'Поместите маркер на карте в точку, с которой вы производили съёмку. Для установки маркера достаточно кликнуть по карте в нужном месте.', + 'UP_NODIR': 'Укажите направление съёмки.', + 'UP_NOCITY': 'Вы не указали город. Нажмите кнопку подтверждения для отправки фотографии, если города съемки нет в списке. Нажмите кнопку отмены, если Вы забыли указать город.', + 'UP_OTHERCITY': 'Город съёмки не соответствует привязанным ТС и/или галереям. Продолжить отправку фото?', + 'UP_ERROR': 'Фото не было загружено :-(', + 'UP_SUCCESS': 'Фотография успешно загружена!', + 'UP_NOTHING': 'К сожалению, ничего подходящего найти не удалось', + 'UP_V_LINKED': 'Это ТС уже привязано к данному фото', + 'UP_G_LINKED': 'Эта галерея уже привязана к данному фото', + 'UP_CREATIVE': 'Фотография, загружаемая в «Фотозарисовки» или «Художественную галерею», не может быть привязана к ТС и другим галереям.', + 'UP_NOLINKS': 'Фотография ни к чему не привязана', + 'UP_NO_PRI': 'Фотография не может иметь только второстепенные привязки.', + 'UP_NODATE': 'Вы не указали дату снимка. Нажмите «OK», если так и должно быть, или «Отмена», если хотите добавить дату съёмки', + 'UP_NOPLACE': 'Вы не указали место съёмки. Нажмите «OK», если так и должно быть, или «Отмена», если хотите добавить место съёмки', + 'UP_ARTICLE': 'Галерея', + 'UP_LIMITEXC': 'Сегодня Вы уже загрузили максимально возможное число фотографий. Следующие фотографии Вы можете загрузить завтра', + 'UP_ROUTE': 'Маршрут', + 'UP_NOTES': 'примечание', + 'VIEW': 'Ракурс', + 'UP_NOVIEW': 'Не для всех ТС указан ракурс съёмки.', + 'UP_TOQUEUE': 'Это фото не может быть опубликовано без модерации, поэтому оно было помещено в очередь', + 'UP_BIND': 'Привязка', + 'UP_BIND_PRI': 'Основная — ТС на переднем плане', + 'UP_BIND_SEC': 'Второстепенная — ТС на заднем плане', + 'UP_BIND_CON': 'Условная — ТС указано предположительно', + 'UP_NAA_ALLOW_NO': 'Не указано разрешение на публикацию.', + 'UP_TWOSIDE': 'Вы выбрали тип ПС (двухсторонний/односторонний), не совпадающий с указанным для данной модели. Так и должно быть?', + 'MAP_SEARCH': 'Адрес или объект...', + 'MAP_NOTFOUND': 'На карте не удалось найти указанное место.', + 'MAP_OSM': 'Карта OpenStreetMap', + 'MAP_OSM_BW': 'Чёрно-белая карта OpenStreetMap', + 'MAP_OSM_HOT': 'Карта Humanitarian OpenStreetMap Team', + 'MAP_TOPO': 'Карта OpenTopoMap', + 'MAP_WIKIMEDIA': 'Карта Wikimedia', + 'MAP_OPNV': 'Карта ÖPNVKarte', + 'MAP_OPENPTMAP': 'Общественный транспорт от OpenPtMap', + 'MAP_RAILWAY': 'Железная дорога от OpenRailwayMap', + 'MAP_BING': 'Спутник Bing', + 'MAP_YANDEX': 'Карта Яндекс', + 'MAP_YANDSAT': 'Спутник Яндекс' +}); + +var views = { + 0: ' Не указан ', +1: 'Спереди-справа (двери)', +2: 'Спереди-слева (окна)', +3: 'Сзади-справа (двери)', +4: 'Сзади-слева (окна)', +5: 'Вид строго спереди', +6: 'Правый борт', +7: 'Вид строго сзади', +8: 'Левый борт', +9: 'Салон, вид вперёд', +10: 'Салон, вид назад', +11: 'Кабина', +12: 'Заводская табличка', +13: 'Отдельные элементы ТС', +14: 'Не определяется (двухстороннее ТС)', +20: 'Вид сверху', +40: 'Вид снизу'}; $(document).ready(function() { @@ -42,29 +121,21 @@ $(document).ready(function() var html = '\n'; html += '\n'; - html += '' + $('.num', this).html() + '\n'; + html += '' + $('.num', this).html() + '\n'; html += '' + $('.mname', this).html() + '\n'; html += '' + _text['UP_ROUTE'] + ':\n'; html += ', \n'; html += '×\n'; html += '\n'; - html += '\n'; - html += '' + cname + '\n'; - html += '' + _text['VIEW'] + ':\n'; - html += '' + views[0] + '\n'; - html += '\n'; + - html += '\n'; - html += '\n'; - html += '' + _text['UP_BIND'] + ':\n'; - html += '' + binds[0].label + '\n'; - html += '\n'; + html += '\n'; var row = $(html); - $('#conn_veh').append(row).show().tablesort('recountRows'); + $('#conn_veh').append(row).show(); $('.pri-label', row).selector2(binds); $('.no-links').hide(); @@ -84,6 +155,11 @@ $(document).ready(function() setTimeout(function() { $('#conn_veh tbody[data-nid="' + nid + '"] .view_link').click(); }, 100); }); + $('#vlist').on('mouseenter mouseleave', '#add_new_vehicle', function() + { + var state = parseInt($(this).data('state')); + $(this).toggleClass('s' + state + ' s' + (state+10)); + }) @@ -225,12 +301,12 @@ function searchVehicles(by_gos) $('#search_cid, #search_type, #search_num, #search_gos').prop('disabled', true); $('#vlist').html('
' + _text['UP_SEARCHING'] + '
').show(); - var data = { cid: $('#search_cid').val(), type: $('#search_type').val(), pub_pid: pub_pid }; + var data = { cid: $('#search_cid').val(), type: $('#search_type').val() }; if (!by_gos) data.num = $('#search_num').val().trim(); else data.gos = $('#search_gos').val().trim(); - $.get('/api.php?action=upload-search-vehicles', data, function (r) + $.get('/api/vehicles/load', data, function (r) { $('#vlist').html(r); $('#search_cid, #search_type, #search_num, #search_gos').prop('disabled', false); @@ -238,6 +314,17 @@ function searchVehicles(by_gos) return false; } +document.onclick = function(e) +{ + e = e || window.event; + E = e.target || e.srcElement; + if (E.id != 'phint' && E.parentNode.id != 'phint' && E != _getID('mform').place) $('#phint').slideUp(); + + if (E.className != 'searchVehiclesBtn' && E.id != 'vlist_table' && E.className != 'num' && $('#vlist').css('display') == 'block') $('#vlist').hide().html(''); + + if ($(E).closest('#views-selector').length == 0) $('#views-selector').hide(); +}; + @@ -300,7 +387,6 @@ function showDefaultCity() keys = Object.keys(cnames); $('#main-cid').val(keys[0]); $('#main-cname').val(cnames[keys[0]]); - selectCity(keys[0]); } } } diff --git a/static/js/selector.js b/static/js/selector.js new file mode 100644 index 0000000..dce350d --- /dev/null +++ b/static/js/selector.js @@ -0,0 +1,211 @@ +function hlText(text, val) +{ + val = val.replace(' -', ' —'); + var p = text.toLowerCase().indexOf(val.toLowerCase()); + if (p != -1) text = text.substring(0, p) + '' + text.substring(p, p + val.length) + '' + text.substring(p + val.length); + return text; +} + + +$(document).ready(function() { $('head').append(''); }); + + +(function($) +{ + $.fn.autocompleteSelector = function(valfield, query, options) + { + if (this.length == 0) return; + + function idToJQ(id) + { + if (!id) return null; + if (id instanceof jQuery) return id; + if (typeof id === 'string' || id instanceof String) return $('#' + id); + return $(id); + } + + var valueField = idToJQ(valfield); + var labelField = this; + + this.savedLabel = this.val(); + var makeBold = (this.css('font-weight') == '700'); + + var defaults = { + minLength: 2, + params: {}, + paramsCallback: null, + selectCallback: null, + focusCallback: null, + blurCallback: null, + renderItem: null, + defaultValue: 0, + defaultLabel: null, + valueName: 'value', + labelName: 'label', + flag: null, + flagValueName: 'rid', + flagLabelName: null, + hlFlag: false, + clearField: false, + method: 'get' + }; + + if (options == undefined) options = {}; + var opts = $.extend({}, defaults, options); + + var flagImg; + if (!opts.flag) + { + if (opts.flagLabelName && valfield && (typeof valfield === 'string' || valfield instanceof String)) + { + flagImg = $('#rid_' + valfield); + if (flagImg.length == 0) flagImg = null; + } + } + else flagImg = idToJQ(opts.flag); + + var xsign; + if (valueField && opts.defaultLabel) + { + xsign = $('
'); + + xsign.insertAfter(labelField).on('click', function() + { + valueField.val(opts.defaultValue); + labelField.val(opts.defaultLabel).trigger('item-select'); + if (opts.selectCallback) opts.selectCallback(null); + }); + + var paddingRight = parseInt(labelField.css('padding-right')); + + function labelFieldChange() + { + if (labelField.val().trim() != opts.defaultLabel.trim()) + { + labelField.css('padding-right', (paddingRight + 22) + 'px'); + xsign.show(); + } + else + { + labelField.css('padding-right', paddingRight); + xsign.hide(); + } + } + + labelField.on('item-select', labelFieldChange); + labelFieldChange(); + } + else xsign = null; + + this.autocomplete({ + minLength: opts.minLength, + source: function(request, response) + { + if (opts.paramsCallback) opts.paramsCallback(opts.params); + opts.params.term = request.term; + + if (opts.method == 'post') + $.post(query, opts.params, response, 'json').fail(function(jx) { if (jx.responseText != '') alert(jx.responseText); }); + else $.get(query, opts.params, response, 'json').fail(function(jx) { if (jx.responseText != '') alert(jx.responseText); }); + }, + focus: function(event, ui) + { + if (event.pageX == undefined) + { + labelField.val(ui.item.label); + return false; + } + }, + select: function(event, ui) + { + if (valueField) valueField.val(ui.item[opts.valueName]); + + if (!opts.clearField) + { + var label = $('
').html(ui.item[opts.labelName]).text(); + labelField.val(label).trigger('item-select'); + labelField.savedLabel = label; + + if (flagImg) flagImg.attr('src', '/img/r/' + ui.item[opts.flagValueName] + '.gif'); + if (makeBold) labelField.css('font-weight', 'bold'); + } + else labelField.val(labelField.savedLabel); + + if (opts.selectCallback) opts.selectCallback(ui.item); + return false; + } + }) + .focus(function() + { + if (valueField) + { + labelField.savedLabel = labelField.val(); + if (makeBold) labelField.css('font-weight', 'normal'); + } + + if (opts.focusCallback) opts.focusCallback(); + }) + .blur(function() + { + var val = labelField.val().trim(); + if (opts.defaultLabel && val == '') + { + if (valueField) valueField.val(opts.defaultValue); + labelField.val(opts.defaultLabel).trigger('item-select'); + if (flagImg) flagImg.attr('src', '/img/r/0.gif'); + if (opts.selectCallback) opts.selectCallback(null); + } + else + if (val != labelField.savedLabel) labelField.val(labelField.savedLabel); + + if (valueField && makeBold) labelField.css('font-weight', 'bold'); + + if (opts.blurCallback) opts.blurCallback(); + }); + + if (!opts.renderItem) + { + if (!opts.flagLabelName) + opts.renderItem = function(ul, item) { return $('
  • ' + hlText(item[opts.labelName], this.element.val()) + '
  • ').appendTo(ul); }; + else opts.renderItem = function(ul, item) { return $('
  •    ' + (item[opts.flagLabelName] != undefined ? (opts.hlFlag ? hlText(item[opts.flagLabelName], this.element.val()) : item[opts.flagLabelName]) + '  ' : '') + '
    ' + hlText(item[opts.labelName], this.element.val()) + '
  • ').appendTo(ul); }; + } + + this.data('ui-autocomplete')._renderItem = opts.renderItem; + this.on('click', function() { if (labelField.savedLabel == this.value) { this.select(); } }); + + return this; + }; + + + $.fn.citySelector = function(valfield, options) + { + if (options == undefined) options = {}; + options.flagLabelName = 'rname'; + options.hlFlag = true; + this.autocompleteSelector(valfield, '/api.php?action=get-cities', options); + }; + + + $.fn.groupSelector = function(valfield, options) + { + if (options == undefined) options = {}; + options.flagLabelName = 'rname'; + options.hlFlag = true; + this.autocompleteSelector(valfield, '/api.php?action=get-groups', options); + }; + + + $.fn.regionSelector = function(valfield, options) + { + if (options == undefined) options = {}; + options.flagValueName = 'value'; + if (!options.renderItem) options.renderItem = function(ul, item) { return $('
  • ' + hlText(item.label, this.element.val()) + '
  • ').appendTo(ul); }; + this.autocompleteSelector(valfield, '/api.php?action=get-regions', options); + }; + + + $.fn.autocompleteHL = function(options) + { + this.autocomplete(options).data('ui-autocomplete')._renderItem = function(ul, item) { return $('
  • ' + hlText(item.label, this.element.val()) + '
  • ').appendTo(ul); }; + } +})(jQuery); diff --git a/static/js/selector2.js b/static/js/selector2.js new file mode 100644 index 0000000..01be21f --- /dev/null +++ b/static/js/selector2.js @@ -0,0 +1,97 @@ +(function($) +{ + $.fn.selector2 = function(items, options) + { + if (this.length == 0) return; + + this.each(function() + { + var labelElement = $(this); + var valueField = $('input', labelElement.parent()); + var currentIndex = -1; + + var defaults = { + selectCallback: null + }; + + if (options == undefined) options = {}; + var opts = $.extend({}, defaults, options); + + + labelElement.on('click', function() + { + var currentValue = valueField.val(); + + var val, html = '
    '; + for (var i = 0; i < items.length; i++) + { + html += '
    '; + } + html += '
    '; + + var helper = $(html).appendTo('body'); + var offset = $(this).offset(); + + helper.css('top', Math.max(0, offset.top - currentIndex * 22 - 1) + 'px'); + helper.css('left', (offset.left - 7) + 'px'); + + helper.on('click', '> div', function() + { + var el = $(this); + var val = el.data('value'); + var idx = el.data('index'); + + valueField.val(val); + labelElement.html(items[idx].label); + if (opts.selectCallback) opts.selectCallback.call(labelElement, val); + + helper.remove(); + $(document).off('.selector2'); + }) + .on('mouseenter', '> div', function() { var el = $(this); el.addClass('hov').siblings().removeClass('hov'); currentIndex = el.data('index'); }); + + $(document).on('click.selector2', function(e) + { + if (!$(e.target).is(helper)) helper.remove(); + $(document).off('.selector2'); + }) + .on('keydown.selector2', function(e) + { + if (e.which == 40 || e.which == 38) + { + e.preventDefault(); + $('> div', helper).removeClass('hov'); + if (e.which == 40 && ++currentIndex == items.length) currentIndex = 0; else + if (e.which == 38 && --currentIndex < 0) currentIndex = items.length - 1; + $('div[data-index="' + currentIndex + '"]', helper).addClass('hov'); + } + else + if ((e.which == 13 || e.which == 32) && currentIndex != -1) + { + e.preventDefault(); + $('div[data-index="' + currentIndex + '"]', helper).trigger('click'); + } + else + if (e.which == 27 || e.which == 8) + { + e.preventDefault(); + helper.remove(); + $(document).off('.selector2'); + } + }); + + helper.show(); + + return false; + }); + }); + + return this; + }; +})(jQuery); diff --git a/static/js/tablesort.js b/static/js/tablesort.js new file mode 100644 index 0000000..6aca9ae --- /dev/null +++ b/static/js/tablesort.js @@ -0,0 +1,193 @@ +/** + * tablesort plugin for jQuery + * Written by Alexander Konov + * Based on TableDnD ideas (https://github.com/isocra/TableDnD) + */ + +(function($) +{ + $.fn.tablesort = function(options) + { + function recountRows(tbl) + { + var opts = tbl.data('opts'); + var rows = $(opts.rowSelector, tbl); + var rowsCount = rows.length; + var handle = (opts.dragHandle ? $(opts.dragHandle, tbl) : tbl); + + tbl.data('rowsCount', rowsCount); + handle[rowsCount > 1 ? 'addClass' : 'removeClass']('tablesort-active'); + + return rows; + } + + + $(this).each(function() + { + var table = $(this); + + // Метод recountRows нужно вызывать извне при добавлении или удалении строк в таблице + // Это требуется для автоотключения сортировки, если в таблице только одна строка + if (typeof options == 'string' && options == 'recountRows') + { + recountRows(table); + return table; + } + + + var eventStart = 'touchstart.tablesort mousedown.tablesort'; + var eventMove = 'touchmove.tablesort mousemove.tablesort'; + var eventEnd = 'touchend.tablesort mouseup.tablesort'; + + var dragObject = null; + var mouseOffset = null; + var oldY = 0; + + var defaults = { + rowSelector: 'tr', // Можно указать tbody, если надо перемещать блоки, состоящие из нескольких строк + dragHandle: null, // Селектор "ручки" для переноса (по умолчанию можно перемещать, потянув за любое место строки, кроме и ) + sensitivity: 10, // Sensitivity setting will throttle the trigger rate for movement detection + onChange: null // Функция onChange + }; + + if (options == undefined) options = {}; + var opts = $.extend({}, defaults, options); + + table.data('opts', opts); + + + if (opts.dragHandle) + table.on(eventStart, opts.dragHandle, function(e) { startDrag($(this).closest(opts.rowSelector), e); }); + else table.on(eventStart, opts.rowSelector, function(e) { startDrag($(this), e); }); + + recountRows(table); + + + function startDrag(dragObj, e) + { + if (table.data('rowsCount') <= 1) return; // Некуда перетаскивать - всего одна строка в таблице + + var target = $(e.target); + if (target.closest('a').length != 0 || target.is('input') || target.is('select') || target.is('textarea')) return; // Неподходящие для перетаскивания элементы с собственным поведением + + e.preventDefault(); + + dragObject = dragObj; + mouseOffset = getMouseY(e) - $(e.target).offset().top; + + $(document).on(eventMove, mouseMove).on(eventEnd, mouseUp); + + $('html').add(opts.dragHandle ? $(opts.dragHandle, table) : table).addClass('tablesort-dragging'); + toggleObjectClass(dragObject); + } + + + function toggleObjectClass(obj) + { + var s = obj.attr('class'); + if (!s) return; + + var i, cls, arr = s.split(' '); + + for (i = 0; i < arr.length; i++) + { + if (/s[0-9]{1,2}/.test(arr[i])) + { + cls = parseInt(arr[i].substr(1)); + arr[i] = 's' + (cls >= 10 && cls <= 19 || cls >= 30 && cls <= 39 ? cls-10 : cls+10); + } + + obj.attr('class', arr.join(' ')); + } + } + + + function getMouseY(e) + { + if (e.originalEvent.changedTouches) return e.originalEvent.changedTouches[0].clientY + $(document).scrollTop(); + if (e.pageY) return e.pageY; + return e.clientY + $(document).scrollTop(); + } + + + function checkPageScroll(e) + { + var y = (e.originalEvent.changedTouches) ? e.originalEvent.changedTouches[0].clientY : e.clientY; + var h = $(window).innerHeight(); + + if (y < 25) window.scrollBy(0, -10); else + if (y > h - 25) window.scrollBy(0, 10); + } + + + function rowMoving(dir, currentRow) + { + if (!dir || !currentRow) return; + currentRow[dir > 0 ? 'after' : 'before'](dragObject); + } + + + function mouseMove(e) + { + if (!dragObject) return false; + e.preventDefault(); + + checkPageScroll(e); + + var mouseY = getMouseY(e); + rowMoving(findDragDirection(mouseY), findDropTargetRow(dragObject, mouseY)); + + return false; + } + + + function findDragDirection(y) + { + var yMin = oldY - opts.sensitivity; + var yMax = oldY + opts.sensitivity; + + var dir = y >= yMin && y <= yMax ? 0 : y > oldY ? 1 : -1; + if (dir) oldY = y; + + return dir; + } + + + function findDropTargetRow(draggedRow, y) + { + var row, rowY; + var rows = recountRows(table); + var rowsCount = table.data('rowsCount'); + + for (var i = 0; i < rowsCount; i++) + { + row = rows.eq(i); + rowY = row.offset().top; + + if (y >= rowY && y <= rowY + row.outerHeight()) return draggedRow.is(row) ? null : row; + } + + return null; + } + + + function mouseUp(e) + { + if (!dragObject) return null; + e.preventDefault(); + + $(document).off(eventMove + ' ' + eventEnd); + + toggleObjectClass(dragObject); + dragObject = null; + + $('html').add('.tablesort-dragging').removeClass('tablesort-dragging'); + + if (opts.onChange) opts.onChange.call(table); + return false; + } + + return table; + }); + } +})(jQuery); \ No newline at end of file diff --git a/views/components/LoadHead.php b/views/components/LoadHead.php index 5217b50..0bf9bc7 100644 --- a/views/components/LoadHead.php +++ b/views/components/LoadHead.php @@ -24,6 +24,9 @@ + + +
    diff --git a/views/pages/Profile/UploadPhoto.php b/views/pages/Profile/UploadPhoto.php index 84af5a6..b92d38d 100644 --- a/views/pages/Profile/UploadPhoto.php +++ b/views/pages/Profile/UploadPhoto.php @@ -20,6 +20,8 @@ $user = new User(Auth::userid()); + + @@ -39,7 +41,7 @@ $user = new User(Auth::userid()); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Предложить медиа на публикацию

    Ваш текущий индекс загрузки: i('uploadindex') ?>

    @@ -261,9 +263,124 @@ $user = new User(Auth::userid()); JPG, JPEG, PNG, GIF, WEBP, MP4, AVI, 3GP, MKV
    Для наибольшей совместимости, ваше видео будет обработано в формат MP4 в кодеке H264 -
    +
    Дата съёмки: @@ -502,7 +619,7 @@ $user = new User(Auth::userid()); '.$g['title'].''; + echo ''; } ?> @@ -544,7 +661,7 @@ $user = new User(Auth::userid());
    - + @@ -552,8 +669,141 @@ $user = new User(Auth::userid());
    +
    + + Привязка: + + + + + + @@ -882,7 +1132,7 @@ $user = new User(Auth::userid()); Комментирование Вашего медиа будет ограничено, однако Вы сможете добавлять к нему свои аннотации вне зависимости от настройки. - + @@ -899,7 +1149,7 @@ $user = new User(Auth::userid()); - + @@ -930,7 +1180,7 @@ $user = new User(Auth::userid()); Ваши подписчики не получат уведомление о публикации Медиа, но они всегда смогут его увидеть из общих топов (если таковая настройка не была отключена
    - + Вы можете всегда в любое время изменить эти настройки. diff --git a/views/pages/Vehicle.php b/views/pages/Vehicle.php index 8f3c186..d763505 100644 --- a/views/pages/Vehicle.php +++ b/views/pages/Vehicle.php @@ -4,7 +4,11 @@ use \App\Services\{Auth, DB, Date}; use \App\Models\Vehicle; $id = explode('/', $_SERVER['REQUEST_URI'])[2]; -$vehicle = new Vehicle($id); +$data = DB::query('SELECT * FROM entities_data WHERE id=:id', array(':id' => $id))[0]; +$vehicle = new Vehicle($data['entityid']); + +$vehicledatavariables = json_decode($data['content'], true); + ?> @@ -12,7 +16,7 @@ $vehicle = new Vehicle($id); - + @@ -24,39 +28,30 @@ $vehicle = new Vehicle($id); -

    Пиксельск, бутылка pepsi № 001

    - +

    + getvehicle('sampledata'), true); + $num = 1; foreach ($vehiclevariables as $vb) { - echo ''; + echo ''; + $num++; } ?> - +
    '.$vb['name'].':1975
    ' . $vb['name'] . ':' . $vehicledatavariables[$num]['value'] . '

    - - - + + + - Главная     Личный кабинет     Форум     Правила     Редколлегия
    - Светлая тема -
    © Администрация ТрансФото и авторы материалов, 2002—2024
    Использование фотографий и иных материалов, опубликованных на сайте, допускается только с разрешения их авторов.
    -
    - - - Яндекс.Метрика - + - -
    - diff --git a/views/pages/t.php b/views/pages/t.php index 5c0ef3e..564d20f 100644 --- a/views/pages/t.php +++ b/views/pages/t.php @@ -1,6 +1,90 @@ - + + + + + Face Detection with TensorFlow.js + + +

    Face Detection using TensorFlow.js

    + +

    + +

    +
    +
    + + + + +