diff --git a/app/Presenters/AccessoryPresenter.php b/app/Presenters/AccessoryPresenter.php
index 5e79cb4a2..6d423bed7 100644
--- a/app/Presenters/AccessoryPresenter.php
+++ b/app/Presenters/AccessoryPresenter.php
@@ -84,13 +84,14 @@ class AccessoryPresenter extends Presenter
'sortable' => true,
'title' => trans('general.min_amt'),
'formatter' => 'minAmtFormatter',
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
], [
'field' => 'qty',
'searchable' => false,
'sortable' => true,
'title' => trans('admin/accessories/general.total'),
'footerFormatter' => 'qtySumFormatter',
+ 'class' => 'text-right text-padding-number-cell',
], [
'field' => 'remaining',
'searchable' => false,
@@ -98,6 +99,7 @@ class AccessoryPresenter extends Presenter
'visible' => false,
'title' => trans('admin/accessories/general.remaining'),
'footerFormatter' => 'qtySumFormatter',
+ 'class' => 'text-right text-padding-number-cell',
],[
'field' => 'checkouts_count',
'searchable' => false,
@@ -105,6 +107,7 @@ class AccessoryPresenter extends Presenter
'visible' => true,
'title' => trans('general.checked_out'),
'footerFormatter' => 'qtySumFormatter',
+ 'class' => 'text-right text-padding-number-cell',
], [
'field' => 'purchase_date',
'searchable' => true,
@@ -118,7 +121,7 @@ class AccessoryPresenter extends Presenter
'sortable' => true,
'title' => trans('general.purchase_cost'),
'footerFormatter' => 'sumFormatterQuantity',
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
], [
'field' => 'order_number',
'searchable' => true,
diff --git a/app/Presenters/AssetModelPresenter.php b/app/Presenters/AssetModelPresenter.php
index 5eaf7dc44..2ed019eae 100644
--- a/app/Presenters/AssetModelPresenter.php
+++ b/app/Presenters/AssetModelPresenter.php
@@ -75,7 +75,7 @@ class AssetModelPresenter extends Presenter
'title' => trans('mail.min_QTY'),
'visible' => true,
'formatter' => 'minAmtFormatter',
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
],
[
@@ -85,7 +85,7 @@ class AssetModelPresenter extends Presenter
'switchable' => true,
'title' => trans('admin/models/table.numassets'),
'visible' => true,
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
],
@@ -96,7 +96,7 @@ class AssetModelPresenter extends Presenter
'switchable' => true,
'title' => trans('general.remaining'),
'visible' => true,
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
],
[
diff --git a/app/Presenters/ComponentPresenter.php b/app/Presenters/ComponentPresenter.php
index 3bdc7728f..61f7a0ef4 100644
--- a/app/Presenters/ComponentPresenter.php
+++ b/app/Presenters/ComponentPresenter.php
@@ -85,7 +85,7 @@ class ComponentPresenter extends Presenter
'sortable' => true,
'title' => trans('general.min_amt'),
'visible' => true,
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
'formatter' => 'minAmtFormatter',
], [
'field' => 'qty',
@@ -93,7 +93,7 @@ class ComponentPresenter extends Presenter
'sortable' => true,
'title' => trans('admin/components/general.total'),
'visible' => true,
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
], [
'field' => 'remaining',
@@ -101,7 +101,7 @@ class ComponentPresenter extends Presenter
'sortable' => false,
'title' => trans('admin/components/general.remaining'),
'visible' => true,
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
], [
'field' => 'location',
diff --git a/app/Presenters/ConsumablePresenter.php b/app/Presenters/ConsumablePresenter.php
index db982cac6..fd4cee272 100644
--- a/app/Presenters/ConsumablePresenter.php
+++ b/app/Presenters/ConsumablePresenter.php
@@ -79,14 +79,14 @@ class ConsumablePresenter extends Presenter
'title' => trans('general.min_amt'),
'visible' => true,
'formatter' => 'minAmtFormatter',
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
], [
'field' => 'qty',
'searchable' => false,
'sortable' => true,
'title' => trans('admin/components/general.total'),
'visible' => true,
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
], [
'field' => 'remaining',
@@ -94,6 +94,7 @@ class ConsumablePresenter extends Presenter
'sortable' => true,
'title' => trans('admin/components/general.remaining'),
'visible' => true,
+ 'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
], [
'field' => 'location',
@@ -128,7 +129,7 @@ class ConsumablePresenter extends Presenter
'title' => trans('general.purchase_cost'),
'visible' => true,
'footerFormatter' => 'sumFormatterQuantity',
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
], [
'field' => 'notes',
'searchable' => true,
diff --git a/app/Presenters/LicensePresenter.php b/app/Presenters/LicensePresenter.php
index a54431a87..f6ccafa8a 100644
--- a/app/Presenters/LicensePresenter.php
+++ b/app/Presenters/LicensePresenter.php
@@ -86,20 +86,20 @@ class LicensePresenter extends Presenter
'sortable' => true,
'title' => trans('mail.min_QTY'),
'formatter' => 'minAmtFormatter',
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
], [
'field' => 'seats',
'searchable' => false,
'sortable' => true,
'title' => trans('admin/accessories/general.total'),
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
], [
'field' => 'free_seats_count',
'searchable' => false,
'sortable' => true,
'title' => trans('admin/accessories/general.remaining'),
- 'class' => 'text-right',
+ 'class' => 'text-right text-padding-number-cell',
'footerFormatter' => 'qtySumFormatter',
], [
'field' => 'purchase_date',
diff --git a/public/css/build/app.css b/public/css/build/app.css
index 7ea8f083b..eb8a1db23 100644
--- a/public/css/build/app.css
+++ b/public/css/build/app.css
@@ -1418,4 +1418,12 @@ input[type="radio"]:checked::before {
.bootstrap-table .fixed-table-container .table tbody tr .card-view {
display: table-row !important;
}
+td.text-right.text-padding-number-cell {
+ padding-right: 30px !important;
+ white-space: nowrap;
+}
+th.text-right.text-padding-number-footer-cell {
+ padding-right: 20px !important;
+ white-space: nowrap;
+}
diff --git a/public/css/build/overrides.css b/public/css/build/overrides.css
index 1074758f2..edf9a25d8 100644
--- a/public/css/build/overrides.css
+++ b/public/css/build/overrides.css
@@ -1049,4 +1049,12 @@ input[type="radio"]:checked::before {
.bootstrap-table .fixed-table-container .table tbody tr .card-view {
display: table-row !important;
}
+td.text-right.text-padding-number-cell {
+ padding-right: 30px !important;
+ white-space: nowrap;
+}
+th.text-right.text-padding-number-footer-cell {
+ padding-right: 20px !important;
+ white-space: nowrap;
+}
diff --git a/public/css/dist/all.css b/public/css/dist/all.css
index 848587ae7..7f8f7a571 100644
--- a/public/css/dist/all.css
+++ b/public/css/dist/all.css
@@ -22753,6 +22753,14 @@ input[type="radio"]:checked::before {
.bootstrap-table .fixed-table-container .table tbody tr .card-view {
display: table-row !important;
}
+td.text-right.text-padding-number-cell {
+ padding-right: 30px !important;
+ white-space: nowrap;
+}
+th.text-right.text-padding-number-footer-cell {
+ padding-right: 20px !important;
+ white-space: nowrap;
+}
.select2-container {
@@ -24288,4 +24296,12 @@ input[type="radio"]:checked::before {
.bootstrap-table .fixed-table-container .table tbody tr .card-view {
display: table-row !important;
}
+td.text-right.text-padding-number-cell {
+ padding-right: 30px !important;
+ white-space: nowrap;
+}
+th.text-right.text-padding-number-footer-cell {
+ padding-right: 20px !important;
+ white-space: nowrap;
+}
diff --git a/public/js/build/app.js b/public/js/build/app.js
index 9bd78d354..1f061aabd 100644
--- a/public/js/build/app.js
+++ b/public/js/build/app.js
@@ -1,799 +1,16 @@
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
-/***/ "./resources/assets/js/bootstrap.js":
-/*!******************************************!*\
- !*** ./resources/assets/js/bootstrap.js ***!
- \******************************************/
-/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
+/***/ "./node_modules/admin-lte/build/less/AdminLTE.less":
+/*!*********************************************************!*\
+ !*** ./node_modules/admin-lte/build/less/AdminLTE.less ***!
+ \*********************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-window._ = __webpack_require__(/*! lodash */ "./node_modules/lodash/lodash.js");
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
-/**
- * We'll load jQuery and the Bootstrap jQuery plugin which provides support
- * for JavaScript based Bootstrap features such as modals and tabs. This
- * code may be modified to fit the specific needs of your application.
- */
-//window.$ = window.jQuery = require('jquery');
-
-/**
- * jQuery UI is loaded here and then the tooltip is assigned another funtion name
- * This resolves the issue of jquery-ui & bootstrap tooltip conflict
- */
-__webpack_require__(/*! jquery-ui */ "./node_modules/jquery-ui/ui/widget.js");
-jQuery.fn.uitooltip = jQuery.fn.tooltip;
-
-/**
- * Load boostrap
- */
-__webpack_require__(/*! bootstrap-less */ "./node_modules/bootstrap-less/js/bootstrap.js");
-
-// require('admin-lte');
-
-// require('chart.js');
-
-// require('jquery-form-validator'); //says something about dependency
-/**
- * Echo exposes an expressive API for subscribing to channels and listening
- * for events that are broadcast by Laravel. Echo and event broadcasting
- * allows your team to easily build robust real-time web applications.
- */
-
-// import Echo from "laravel-echo"
-
-// window.Echo = new Echo({
-// broadcaster: 'pusher',
-// key: 'your-pusher-key'
-// });
-
-/***/ }),
-
-/***/ "./resources/assets/js/snipeit.js":
-/*!****************************************!*\
- !*** ./resources/assets/js/snipeit.js ***!
- \****************************************/
-/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
-
-// var jQuery = require('jquery');
-// window.jQuery = jQuery
-// window.$ = jQuery
-
-__webpack_require__(/*! ./bootstrap */ "./resources/assets/js/bootstrap.js");
-
-/**
- * Module containing core application logic.
- * @param {jQuery} $ Insulated jQuery object
- * @param {JSON} settings Insulated `window.snipeit.settings` object.
- * @return {IIFE} Immediately invoked. Returns self.
- */
-
-lineOptions = {
- legend: {
- position: "bottom"
- },
- scales: {
- yAxes: [{
- ticks: {
- fontColor: "rgba(0,0,0,0.5)",
- fontStyle: "bold",
- beginAtZero: true,
- maxTicksLimit: 5,
- padding: 20
- },
- gridLines: {
- drawTicks: false,
- display: false
- }
- }],
- xAxes: [{
- gridLines: {
- zeroLineColor: "transparent"
- },
- ticks: {
- padding: 20,
- fontColor: "rgba(0,0,0,0.5)",
- fontStyle: "bold"
- }
- }]
- }
-};
-pieOptions = {
- //Boolean - Whether we should show a stroke on each segment
- segmentShowStroke: true,
- //String - The colour of each segment stroke
- segmentStrokeColor: "#fff",
- //Number - The width of each segment stroke
- segmentStrokeWidth: 1,
- //Number - The percentage of the chart that we cut out of the middle
- percentageInnerCutout: 50,
- // This is 0 for Pie charts
- //Number - Amount of animation steps
- animationSteps: 100,
- //String - Animation easing effect
- animationEasing: "easeOutBounce",
- //Boolean - Whether we animate the rotation of the Doughnut
- animateRotate: true,
- //Boolean - Whether we animate scaling the Doughnut from the centre
- animateScale: false,
- //Boolean - whether to make the chart responsive to window resizing
- responsive: true,
- // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
- maintainAspectRatio: false,
- //String - A legend template
- legendTemplate: "
-legend\"><% for (var i=0; i- " + "" + "<%if(segments[i].label){%><%=segments[i].label%><%}%> foo
<%}%>
",
- //String - A tooltip template
- tooltipTemplate: "<%=value %> <%=label%> "
-};
-
-//-----------------
-//- END PIE CHART -
-//-----------------
-
-var baseUrl = $('meta[name="baseUrl"]').attr('content');
-$(function () {
- var $el = $('table');
-
- // confirm restore modal
-
- $el.on('click', '.restore-asset', function (evnt) {
- var $context = $(this);
- var $restoreConfirmModal = $('#restoreConfirmModal');
- var href = $context.attr('href');
- var message = $context.attr('data-content');
- var title = $context.attr('data-title');
- $('#confirmModalLabel').text(title);
- $restoreConfirmModal.find('.modal-body').text(message);
- $('#restoreForm').attr('action', href);
- $restoreConfirmModal.modal({
- show: true
- });
- return false;
- });
-
- // confirm delete modal
-
- $el.on('click', '.delete-asset', function (evnt) {
- var $context = $(this);
- var $dataConfirmModal = $('#dataConfirmModal');
- var href = $context.attr('href');
- var message = $context.attr('data-content');
- var title = $context.attr('data-title');
- $('#myModalLabel').text(title);
- $dataConfirmModal.find('.modal-body').text(message);
- $('#deleteForm').attr('action', href);
- $dataConfirmModal.modal({
- show: true
- });
- return false;
- });
-
- /*
- * Slideout help menu
- */
- $('.slideout-menu-toggle').on('click', function (event) {
- event.preventDefault();
- // create menu variables
- var slideoutMenu = $('.slideout-menu');
- var slideoutMenuWidth = $('.slideout-menu').width();
-
- // toggle open class
- slideoutMenu.toggleClass("open");
-
- // slide menu
- if (slideoutMenu.hasClass("open")) {
- slideoutMenu.show();
- slideoutMenu.animate({
- right: "0px"
- });
- } else {
- slideoutMenu.animate({
- right: -slideoutMenuWidth
- }, "-350px");
- slideoutMenu.fadeOut();
- }
- });
-
- /*
- * Select2
- */
-
- $('select.select2:not(".select2-hidden-accessible")').each(function (i, obj) {
- {
- $(obj).select2();
- }
- });
-
- // $('.datepicker').datepicker();
- // var datepicker = $.fn.datepicker.noConflict(); // return $.fn.datepicker to previously assigned value
- // $.fn.bootstrapDP = datepicker;
- // $('.datepicker').datepicker();
-
- // Crazy select2 rich dropdowns with images!
- $('.js-data-ajax').each(function (i, item) {
- var link = $(item);
- var endpoint = link.data("endpoint");
- var select = link.data("select");
- link.select2({
- /**
- * Adds an empty placeholder, allowing every select2 instance to be cleared.
- * This placeholder can be overridden with the "data-placeholder" attribute.
- */
- placeholder: '',
- allowClear: true,
- language: $('meta[name="language"]').attr('content'),
- dir: $('meta[name="language-direction"]').attr('content'),
- ajax: {
- // the baseUrl includes a trailing slash
- url: baseUrl + 'api/v1/' + endpoint + '/selectlist',
- dataType: 'json',
- delay: 250,
- headers: {
- "X-Requested-With": 'XMLHttpRequest',
- "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
- },
- data: function data(params) {
- var data = {
- search: params.term,
- page: params.page || 1,
- assetStatusType: link.data("asset-status-type")
- };
- return data;
- },
- /* processResults: function (data, params) {
- params.page = params.page || 1;
- var answer = {
- results: data.items,
- pagination: {
- more: data.pagination.more
- }
- };
- return answer;
- }, */
- cache: true
- },
- //escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
- templateResult: formatDatalistSafe
- //templateSelection: formatDataSelection
- });
- });
- function getSelect2Value(element) {
- // if the passed object is not a jquery object, assuming 'element' is a selector
- if (!(element instanceof jQuery)) element = $(element);
- var select = element.data("select2");
-
- // There's two different locations where the select2-generated input element can be.
- searchElement = select.dropdown.$search || select.$container.find(".select2-search__field");
- var value = searchElement.val();
- return value;
- }
- $(".select2-hidden-accessible").on('select2:selecting', function (e) {
- var data = e.params.args.data;
- var isMouseUp = false;
- var element = $(this);
- var value = getSelect2Value(element);
- if (e.params.args.originalEvent) isMouseUp = e.params.args.originalEvent.type == "mouseup";
-
- // if selected item does not match typed text, do not allow it to pass - force close for ajax.
- if (!isMouseUp) {
- if (value.toLowerCase() && data.text.toLowerCase().indexOf(value) < 0) {
- e.preventDefault();
- element.select2('close');
-
- // if it does match, we set a flag in the event (which gets passed to subsequent events), telling it not to worry about the ajax
- } else if (value.toLowerCase() && data.text.toLowerCase().indexOf(value) > -1) {
- e.params.args.noForceAjax = true;
- }
- }
- });
- $(".select2-hidden-accessible").on('select2:closing', function (e) {
- var element = $(this);
- var value = getSelect2Value(element);
- var noForceAjax = false;
- var isMouseUp = false;
- if (e.params.args.originalSelect2Event) noForceAjax = e.params.args.originalSelect2Event.noForceAjax;
- if (e.params.args.originalEvent) isMouseUp = e.params.args.originalEvent.type == "mouseup";
- if (value && !noForceAjax && !isMouseUp) {
- var endpoint = element.data("endpoint");
- var assetStatusType = element.data("asset-status-type");
- $.ajax({
- url: baseUrl + 'api/v1/' + endpoint + '/selectlist?search=' + value + '&page=1' + (assetStatusType ? '&assetStatusType=' + assetStatusType : ''),
- dataType: 'json',
- headers: {
- "X-Requested-With": 'XMLHttpRequest',
- "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
- }
- }).done(function (response) {
- var currentlySelected = element.select2('data').map(function (x) {
- return +x.id;
- }).filter(function (x) {
- return x !== 0;
- });
-
- // makes sure we're not selecting the same thing twice for multiples
- var filteredResponse = response.results.filter(function (item) {
- return currentlySelected.indexOf(+item.id) < 0;
- });
- var first = currentlySelected.length > 0 ? filteredResponse[0] : response.results[0];
- if (first && first.id) {
- first.selected = true;
- if ($("option[value='" + first.id + "']", element).length < 1) {
- var option = new Option(first.text, first.id, true, true);
- element.append(option);
- } else {
- var isMultiple = element.attr("multiple") == "multiple";
- element.val(isMultiple ? element.val().concat(first.id) : element.val(first.id));
- }
- element.trigger('change');
- element.trigger({
- type: 'select2:select',
- params: {
- data: first
- }
- });
- }
- });
- }
- });
- function formatDatalist(datalist) {
- var loading_markup = ' Loading...';
- if (datalist.loading) {
- return loading_markup;
- }
- var markup = '';
- markup += '
';
- if (datalist.image) {
- markup += "
";
- } else {
- markup += '
';
- }
- markup += "
" + datalist.text + "
";
- markup += "
";
- return markup;
- }
- function formatDatalistSafe(datalist) {
- // console.warn("What in the hell is going on with Select2?!?!!?!?");
- // console.warn($.select2);
- if (datalist.loading) {
- return $(' Loading...');
- }
- var root_div = $("");
- var left_pull = $("
");
- if (datalist.image) {
- var inner_div = $("
");
- /******************************************************************
- *
- * We are specifically chosing empty alt-text below, because this
- * image conveys no additional information, relative to the text
- * that will *always* be there in any select2 list that is in use
- * in Snipe-IT. If that changes, we would probably want to change
- * some signatures of some functions, but right now, we don't want
- * screen readers to say "HP SuperJet 5000, .... picture of HP
- * SuperJet 5000..." and so on, for every single row in a list of
- * assets or models or whatever.
- *
- *******************************************************************/
- var img = $("
![]()
");
- // console.warn("Img is: ");
- // console.dir(img);
- // console.warn("Strigularly, that's: ");
- // console.log(img);
- img.attr("src", datalist.image);
- inner_div.append(img);
- } else {
- var inner_div = $("
");
- }
- left_pull.append(inner_div);
- root_div.append(left_pull);
- var name_div = $("
");
- name_div.text(datalist.text);
- root_div.append(name_div);
- var safe_html = root_div.get(0).outerHTML;
- var old_html = formatDatalist(datalist);
- if (safe_html != old_html) {
- //console.log("HTML MISMATCH: ");
- //console.log("FormatDatalistSafe: ");
- // console.dir(root_div.get(0));
- //console.log(safe_html);
- //console.log("FormatDataList: ");
- //console.log(old_html);
- }
- return root_div;
- }
- function formatDataSelection(datalist) {
- // This a heinous workaround for a known bug in Select2.
- // Without this, the rich selectlists are vulnerable to XSS.
- // Many thanks to @uberbrady for this fix. It ain't pretty,
- // but it resolves the issue until Select2 addresses it on their end.
- //
- // Bug was reported in 2016 :{
- // https://github.com/select2/select2/issues/4587
-
- return datalist.text.replace(/>/g, '>').replace(/Click me
- $('a[data-toggle="tab"]').click(function (e) {
- var href = $(this).attr("href");
- history.pushState(null, null, href);
- e.preventDefault();
- $('a[href="' + $(this).attr('href') + '"]').tab('show');
- });
-
- // ------------------------------------------------
- // End Deep Linking for Bootstrap tabs
- // ------------------------------------------------
-
- // Image preview
- function readURL(input, $preview) {
- if (input.files && input.files[0]) {
- var reader = new FileReader();
- reader.onload = function (e) {
- $preview.attr('src', e.target.result);
- };
- reader.readAsDataURL(input.files[0]);
- }
- }
- function formatBytes(bytes) {
- if (bytes < 1024) return bytes + " Bytes";else if (bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB";else if (bytes < 1073741824) return (bytes / 1048576).toFixed(2) + " MB";else return (bytes / 1073741824).toFixed(2) + " GB";
- }
-
- // File size validation
- $('.js-uploadFile').bind('change', function () {
- var $this = $(this);
- var id = '#' + $this.attr('id');
- var status = id + '-status';
- var $status = $(status);
- var delete_id = $(id + '-deleteCheckbox');
- var preview_container = $(id + '-previewContainer');
- $status.removeClass('text-success').removeClass('text-danger');
- $(status + ' .goodfile').remove();
- $(status + ' .badfile').remove();
- $(status + ' .previewSize').hide();
- preview_container.hide();
- $(id + '-info').html('');
- var max_size = $this.data('maxsize');
- var total_size = 0;
- for (var i = 0; i < this.files.length; i++) {
- total_size += this.files[i].size;
- $(id + '-info').append('
' + htmlEntities(this.files[i].name) + ' (' + formatBytes(this.files[i].size) + ') ');
- }
- if (total_size > max_size) {
- $status.addClass('text-danger').removeClass('help-block').prepend('
').append('
Upload is ' + formatBytes(total_size) + '.');
- } else {
- $status.addClass('text-success').removeClass('help-block').prepend('
');
- var $preview = $(id + '-imagePreview');
- readURL(this, $preview);
- $preview.fadeIn();
- preview_container.fadeIn();
- delete_id.hide();
- }
- });
-});
-function htmlEntities(str) {
- return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
-}
-
-/**
- * Toggle disabled
- */
-(function ($) {
- $.fn.toggleDisabled = function (callback) {
- return this.each(function () {
- var disabled,
- $this = $(this);
- if ($this.attr('disabled')) {
- $this.removeAttr('disabled');
- disabled = false;
- } else {
- $this.attr('disabled', 'disabled');
- disabled = true;
- }
- if (callback && typeof callback === 'function') {
- callback(this, disabled);
- }
- });
- };
-})(jQuery);
-
-/**
- * Universal Livewire Select2 integration
- *
- * How to use:
- *
- * 1. Set the class of your select2 elements to 'livewire-select2').
- * 2. Name your element to match a property in your Livewire component
- * 3. Add an attribute called 'data-livewire-component' that points to $this->getId() (via `{{ }}` if you're in a blade,
- * or just $this->getId() if not).
- */
-document.addEventListener('livewire:init', function () {
- $('.livewire-select2').select2();
- $(document).on('select2:select', '.livewire-select2', function (event) {
- var target = $(event.target);
- if (!event.target.name || !target.data('livewire-component')) {
- console.error("You need to set both name (which should match a Livewire property) and data-livewire-component on your Livewire-ed select2 elements!");
- console.error("For data-livewire-component, you probably want to use $this->getId() or {{ $this->getId() }}, as appropriate");
- return false;
- }
- Livewire.find(target.data('livewire-component')).set(event.target.name, this.options[this.selectedIndex].value);
- });
- Livewire.hook('request', function (_ref) {
- var succeed = _ref.succeed;
- succeed(function () {
- queueMicrotask(function () {
- $('.livewire-select2').select2();
- });
- });
- });
-});
-
-/***/ }),
-
-/***/ "./resources/assets/js/snipeit_modals.js":
-/*!***********************************************!*\
- !*** ./resources/assets/js/snipeit_modals.js ***!
- \***********************************************/
-/***/ (() => {
-
-/*
- *
- * Snipe-IT Universal Modal support
- *
- * Enables modal dialogs to create sub-resources throughout Snipe-IT
- *
- */
-
-/*
-HOW TO USE
- Create a Button looking like this:
-
New
- If you don't have access to Blade commands (like {{ and }}, etc), you can hard-code a URL as the 'href'
- data-toggle="modal" - required for Bootstrap Modals
-data-target="#createModal" - fixed ID for the modal, do not change
-data-select="assigned_to" - What is the *ID* of the select-dropdown that you're going to be adding to, if the modal-create was a success? Be on the lookout for duplicate ID's, it will confuse this library!
-class="btn btn-sm btn-primary" - makes it look button-ey, feel free to change :)
-
-If you want to pass additional variables to the modal (In the Category Create one, for example, you can pass category_id), you can encode them as URL variables in the href
-
-*/
-
-$(function () {
- var baseUrl = $('meta[name="baseUrl"]').attr('content');
- //handle modal-add-interstitial calls
- var model, select, refreshSelector;
- if ($('#createModal').length == 0) {
- $('body').append('
');
- }
- $('#createModal').on("show.bs.modal", function (event) {
- var link = $(event.relatedTarget);
- model = link.data("dependency");
- select = link.data("select");
- refreshSelector = link.data("refresh");
- $('#createModal').load(link.attr('href'), function () {
- // this sets the focus to be the name field
- $('#modal-name').focus();
-
- //do we need to re-select2 this, after load? Probably.
- $('#createModal').find('select.select2').select2();
- // Initialize the ajaxy select2 with images.
- // This is a copy/paste of the code from snipeit.js, would be great to only have this in one place.
-
- $('.js-data-ajax').each(function (i, item) {
- var link = $(item);
- var endpoint = link.data("endpoint");
- var select = link.data("select");
- link.select2({
- ajax: {
- // the baseUrl includes a trailing slash
- url: baseUrl + 'api/v1/' + endpoint + '/selectlist',
- //WARNING - we're hoping that's defined on the page somewhere...
- dataType: 'json',
- delay: 250,
- headers: {
- "X-Requested-With": 'XMLHttpRequest',
- "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
- },
- data: function data(params) {
- var data = {
- search: params.term,
- page: params.page || 1,
- assetStatusType: link.data("asset-status-type")
- };
- return data;
- },
- /*processResults: function (data, params) {
- params.page = params.page || 1;
- var answer = {
- results: data.items,
- pagination: {
- more: data.pagination.more
- }
- };
- return answer;
- },*/
- cache: true
- },
- //escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
- templateResult: formatDatalistSafe
- //templateSelection: formatDataSelection
- });
- });
- });
- });
- $('#createModal').on('click', '#modal-save', function () {
- $.ajax({
- type: 'POST',
- url: $('.modal-body form').attr('action'),
- headers: {
- "X-Requested-With": 'XMLHttpRequest',
- "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
- },
- data: $('.modal-body form').serialize(),
- success: function success(result) {
- if (result.status == "error") {
- var error_message = "";
- for (var field in result.messages) {
- error_message += "
Problem(s) with field " + field + ": " + result.messages[field];
- }
- $('#modal_error_msg').html(error_message).show();
- return false;
- }
- var id = result.payload.id;
- var name = result.payload.name || result.payload.first_name + " " + result.payload.last_name;
- if (!id || !name) {
- console.error("Could not find resulting name or ID from modal-create. Name: " + name + ", id: " + id);
- return false;
- }
- $('#createModal').modal('hide');
- $('#createModal').html("");
- var refreshTable = $('#' + refreshSelector);
- if (refreshTable.length > 0) {
- refreshTable.bootstrapTable('refresh');
- }
-
- // "select" is the original drop-down menu that someone
- // clicked 'add' on to add a new 'thing'
- // this code adds the newly created object to that select
- var selector = document.getElementById(select);
- if (!selector) {
- return false;
- }
- selector.options[selector.length] = new Option(name, id);
- selector.selectedIndex = selector.length - 1;
- $(selector).trigger("change");
- if (window.fetchCustomFields) {
- fetchCustomFields();
- }
- },
- error: function error(result) {
- msg = result.responseJSON.messages || result.responseJSON.error;
- $('#modal_error_msg').html("Server Error: " + msg).show();
- }
- });
- });
-});
-function formatDatalistSafe(datalist) {
- // console.warn("What in the hell is going on with Select2?!?!!?!?");
- // console.warn($.select2);
- if (datalist.loading) {
- return $(' Loading...');
- }
- var root_div = $("");
- var left_pull = $("
");
- if (datalist.image) {
- var inner_div = $("
");
- /******************************************************************
- *
- * We are specifically chosing empty alt-text below, because this
- * image conveys no additional information, relative to the text
- * that will *always* be there in any select2 list that is in use
- * in Snipe-IT. If that changes, we would probably want to change
- * some signatures of some functions, but right now, we don't want
- * screen readers to say "HP SuperJet 5000, .... picture of HP
- * SuperJet 5000..." and so on, for every single row in a list of
- * assets or models or whatever.
- *
- *******************************************************************/
- var img = $("
![]()
");
- // console.warn("Img is: ");
- // console.dir(img);
- // console.warn("Strigularly, that's: ");
- // console.log(img);
- img.attr("src", datalist.image);
- inner_div.append(img);
- } else {
- var inner_div = $("
");
- }
- left_pull.append(inner_div);
- root_div.append(left_pull);
- var name_div = $("
");
- name_div.text(datalist.text);
- root_div.append(name_div);
- var safe_html = root_div.get(0).outerHTML;
- var old_html = formatDatalist(datalist);
- if (safe_html != old_html) {
- // console.log("HTML MISMATCH: ");
- // console.log("FormatDatalistSafe: ");
- // console.dir(root_div.get(0));
- // console.log(safe_html);
- // console.log("FormatDataList: ");
- // console.log(old_html);
- }
- return root_div;
-}
-function formatDatalist(datalist) {
- var loading_markup = '
Loading...';
- if (datalist.loading) {
- return loading_markup;
- }
- var markup = "
";
- markup += "
";
- if (datalist.image) {
- markup += "
";
- } else {
- markup += "
";
- }
- markup += "
" + datalist.text + "
";
- markup += "
";
- return markup;
-}
-function formatDataSelection(datalist) {
- return datalist.text.replace(/>/g, '>').replace(/ {
+
+window._ = __webpack_require__(/*! lodash */ "./node_modules/lodash/lodash.js");
+
+/**
+ * We'll load jQuery and the Bootstrap jQuery plugin which provides support
+ * for JavaScript based Bootstrap features such as modals and tabs. This
+ * code may be modified to fit the specific needs of your application.
+ */
+//window.$ = window.jQuery = require('jquery');
+
+/**
+ * jQuery UI is loaded here and then the tooltip is assigned another funtion name
+ * This resolves the issue of jquery-ui & bootstrap tooltip conflict
+ */
+__webpack_require__(/*! jquery-ui */ "./node_modules/jquery-ui/ui/widget.js");
+jQuery.fn.uitooltip = jQuery.fn.tooltip;
+
+/**
+ * Load boostrap
+ */
+__webpack_require__(/*! bootstrap-less */ "./node_modules/bootstrap-less/js/bootstrap.js");
+
+// require('admin-lte');
+
+// require('chart.js');
+
+// require('jquery-form-validator'); //says something about dependency
+/**
+ * Echo exposes an expressive API for subscribing to channels and listening
+ * for events that are broadcast by Laravel. Echo and event broadcasting
+ * allows your team to easily build robust real-time web applications.
+ */
+
+// import Echo from "laravel-echo"
+
+// window.Echo = new Echo({
+// broadcaster: 'pusher',
+// key: 'your-pusher-key'
+// });
+
+/***/ }),
+
+/***/ "./resources/assets/js/snipeit.js":
+/*!****************************************!*\
+ !*** ./resources/assets/js/snipeit.js ***!
+ \****************************************/
+/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
+
+// var jQuery = require('jquery');
+// window.jQuery = jQuery
+// window.$ = jQuery
+
+__webpack_require__(/*! ./bootstrap */ "./resources/assets/js/bootstrap.js");
+
+/**
+ * Module containing core application logic.
+ * @param {jQuery} $ Insulated jQuery object
+ * @param {JSON} settings Insulated `window.snipeit.settings` object.
+ * @return {IIFE} Immediately invoked. Returns self.
+ */
+
+lineOptions = {
+ legend: {
+ position: "bottom"
+ },
+ scales: {
+ yAxes: [{
+ ticks: {
+ fontColor: "rgba(0,0,0,0.5)",
+ fontStyle: "bold",
+ beginAtZero: true,
+ maxTicksLimit: 5,
+ padding: 20
+ },
+ gridLines: {
+ drawTicks: false,
+ display: false
+ }
+ }],
+ xAxes: [{
+ gridLines: {
+ zeroLineColor: "transparent"
+ },
+ ticks: {
+ padding: 20,
+ fontColor: "rgba(0,0,0,0.5)",
+ fontStyle: "bold"
+ }
+ }]
+ }
+};
+pieOptions = {
+ //Boolean - Whether we should show a stroke on each segment
+ segmentShowStroke: true,
+ //String - The colour of each segment stroke
+ segmentStrokeColor: "#fff",
+ //Number - The width of each segment stroke
+ segmentStrokeWidth: 1,
+ //Number - The percentage of the chart that we cut out of the middle
+ percentageInnerCutout: 50,
+ // This is 0 for Pie charts
+ //Number - Amount of animation steps
+ animationSteps: 100,
+ //String - Animation easing effect
+ animationEasing: "easeOutBounce",
+ //Boolean - Whether we animate the rotation of the Doughnut
+ animateRotate: true,
+ //Boolean - Whether we animate scaling the Doughnut from the centre
+ animateScale: false,
+ //Boolean - whether to make the chart responsive to window resizing
+ responsive: true,
+ // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
+ maintainAspectRatio: false,
+ //String - A legend template
+ legendTemplate: "
-legend\"><% for (var i=0; i- " + "" + "<%if(segments[i].label){%><%=segments[i].label%><%}%> foo
<%}%>
",
+ //String - A tooltip template
+ tooltipTemplate: "<%=value %> <%=label%> "
+};
+
+//-----------------
+//- END PIE CHART -
+//-----------------
+
+var baseUrl = $('meta[name="baseUrl"]').attr('content');
+$(function () {
+ var $el = $('table');
+
+ // confirm restore modal
+
+ $el.on('click', '.restore-asset', function (evnt) {
+ var $context = $(this);
+ var $restoreConfirmModal = $('#restoreConfirmModal');
+ var href = $context.attr('href');
+ var message = $context.attr('data-content');
+ var title = $context.attr('data-title');
+ $('#confirmModalLabel').text(title);
+ $restoreConfirmModal.find('.modal-body').text(message);
+ $('#restoreForm').attr('action', href);
+ $restoreConfirmModal.modal({
+ show: true
+ });
+ return false;
+ });
+
+ // confirm delete modal
+
+ $el.on('click', '.delete-asset', function (evnt) {
+ var $context = $(this);
+ var $dataConfirmModal = $('#dataConfirmModal');
+ var href = $context.attr('href');
+ var message = $context.attr('data-content');
+ var title = $context.attr('data-title');
+ $('#myModalLabel').text(title);
+ $dataConfirmModal.find('.modal-body').text(message);
+ $('#deleteForm').attr('action', href);
+ $dataConfirmModal.modal({
+ show: true
+ });
+ return false;
+ });
+
+ /*
+ * Slideout help menu
+ */
+ $('.slideout-menu-toggle').on('click', function (event) {
+ event.preventDefault();
+ // create menu variables
+ var slideoutMenu = $('.slideout-menu');
+ var slideoutMenuWidth = $('.slideout-menu').width();
+
+ // toggle open class
+ slideoutMenu.toggleClass("open");
+
+ // slide menu
+ if (slideoutMenu.hasClass("open")) {
+ slideoutMenu.show();
+ slideoutMenu.animate({
+ right: "0px"
+ });
+ } else {
+ slideoutMenu.animate({
+ right: -slideoutMenuWidth
+ }, "-350px");
+ slideoutMenu.fadeOut();
+ }
+ });
+
+ /*
+ * Select2
+ */
+
+ $('select.select2:not(".select2-hidden-accessible")').each(function (i, obj) {
+ {
+ $(obj).select2();
+ }
+ });
+
+ // $('.datepicker').datepicker();
+ // var datepicker = $.fn.datepicker.noConflict(); // return $.fn.datepicker to previously assigned value
+ // $.fn.bootstrapDP = datepicker;
+ // $('.datepicker').datepicker();
+
+ // Crazy select2 rich dropdowns with images!
+ $('.js-data-ajax').each(function (i, item) {
+ var link = $(item);
+ var endpoint = link.data("endpoint");
+ var select = link.data("select");
+ link.select2({
+ /**
+ * Adds an empty placeholder, allowing every select2 instance to be cleared.
+ * This placeholder can be overridden with the "data-placeholder" attribute.
+ */
+ placeholder: '',
+ allowClear: true,
+ language: $('meta[name="language"]').attr('content'),
+ dir: $('meta[name="language-direction"]').attr('content'),
+ ajax: {
+ // the baseUrl includes a trailing slash
+ url: baseUrl + 'api/v1/' + endpoint + '/selectlist',
+ dataType: 'json',
+ delay: 250,
+ headers: {
+ "X-Requested-With": 'XMLHttpRequest',
+ "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
+ },
+ data: function data(params) {
+ var data = {
+ search: params.term,
+ page: params.page || 1,
+ assetStatusType: link.data("asset-status-type")
+ };
+ return data;
+ },
+ /* processResults: function (data, params) {
+ params.page = params.page || 1;
+ var answer = {
+ results: data.items,
+ pagination: {
+ more: data.pagination.more
+ }
+ };
+ return answer;
+ }, */
+ cache: true
+ },
+ //escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
+ templateResult: formatDatalistSafe
+ //templateSelection: formatDataSelection
+ });
+ });
+ function getSelect2Value(element) {
+ // if the passed object is not a jquery object, assuming 'element' is a selector
+ if (!(element instanceof jQuery)) element = $(element);
+ var select = element.data("select2");
+
+ // There's two different locations where the select2-generated input element can be.
+ searchElement = select.dropdown.$search || select.$container.find(".select2-search__field");
+ var value = searchElement.val();
+ return value;
+ }
+ $(".select2-hidden-accessible").on('select2:selecting', function (e) {
+ var data = e.params.args.data;
+ var isMouseUp = false;
+ var element = $(this);
+ var value = getSelect2Value(element);
+ if (e.params.args.originalEvent) isMouseUp = e.params.args.originalEvent.type == "mouseup";
+
+ // if selected item does not match typed text, do not allow it to pass - force close for ajax.
+ if (!isMouseUp) {
+ if (value.toLowerCase() && data.text.toLowerCase().indexOf(value) < 0) {
+ e.preventDefault();
+ element.select2('close');
+
+ // if it does match, we set a flag in the event (which gets passed to subsequent events), telling it not to worry about the ajax
+ } else if (value.toLowerCase() && data.text.toLowerCase().indexOf(value) > -1) {
+ e.params.args.noForceAjax = true;
+ }
+ }
+ });
+ $(".select2-hidden-accessible").on('select2:closing', function (e) {
+ var element = $(this);
+ var value = getSelect2Value(element);
+ var noForceAjax = false;
+ var isMouseUp = false;
+ if (e.params.args.originalSelect2Event) noForceAjax = e.params.args.originalSelect2Event.noForceAjax;
+ if (e.params.args.originalEvent) isMouseUp = e.params.args.originalEvent.type == "mouseup";
+ if (value && !noForceAjax && !isMouseUp) {
+ var endpoint = element.data("endpoint");
+ var assetStatusType = element.data("asset-status-type");
+ $.ajax({
+ url: baseUrl + 'api/v1/' + endpoint + '/selectlist?search=' + value + '&page=1' + (assetStatusType ? '&assetStatusType=' + assetStatusType : ''),
+ dataType: 'json',
+ headers: {
+ "X-Requested-With": 'XMLHttpRequest',
+ "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
+ }
+ }).done(function (response) {
+ var currentlySelected = element.select2('data').map(function (x) {
+ return +x.id;
+ }).filter(function (x) {
+ return x !== 0;
+ });
+
+ // makes sure we're not selecting the same thing twice for multiples
+ var filteredResponse = response.results.filter(function (item) {
+ return currentlySelected.indexOf(+item.id) < 0;
+ });
+ var first = currentlySelected.length > 0 ? filteredResponse[0] : response.results[0];
+ if (first && first.id) {
+ first.selected = true;
+ if ($("option[value='" + first.id + "']", element).length < 1) {
+ var option = new Option(first.text, first.id, true, true);
+ element.append(option);
+ } else {
+ var isMultiple = element.attr("multiple") == "multiple";
+ element.val(isMultiple ? element.val().concat(first.id) : element.val(first.id));
+ }
+ element.trigger('change');
+ element.trigger({
+ type: 'select2:select',
+ params: {
+ data: first
+ }
+ });
+ }
+ });
+ }
+ });
+ function formatDatalist(datalist) {
+ var loading_markup = '
Loading...';
+ if (datalist.loading) {
+ return loading_markup;
+ }
+ var markup = '
';
+ markup += '
';
+ if (datalist.image) {
+ markup += "
";
+ } else {
+ markup += '
';
+ }
+ markup += "
" + datalist.text + "
";
+ markup += "
";
+ return markup;
+ }
+ function formatDatalistSafe(datalist) {
+ // console.warn("What in the hell is going on with Select2?!?!!?!?");
+ // console.warn($.select2);
+ if (datalist.loading) {
+ return $('
Loading...');
+ }
+ var root_div = $("
");
+ var left_pull = $("
");
+ if (datalist.image) {
+ var inner_div = $("
");
+ /******************************************************************
+ *
+ * We are specifically chosing empty alt-text below, because this
+ * image conveys no additional information, relative to the text
+ * that will *always* be there in any select2 list that is in use
+ * in Snipe-IT. If that changes, we would probably want to change
+ * some signatures of some functions, but right now, we don't want
+ * screen readers to say "HP SuperJet 5000, .... picture of HP
+ * SuperJet 5000..." and so on, for every single row in a list of
+ * assets or models or whatever.
+ *
+ *******************************************************************/
+ var img = $("
![]()
");
+ // console.warn("Img is: ");
+ // console.dir(img);
+ // console.warn("Strigularly, that's: ");
+ // console.log(img);
+ img.attr("src", datalist.image);
+ inner_div.append(img);
+ } else {
+ var inner_div = $("
");
+ }
+ left_pull.append(inner_div);
+ root_div.append(left_pull);
+ var name_div = $("
");
+ name_div.text(datalist.text);
+ root_div.append(name_div);
+ var safe_html = root_div.get(0).outerHTML;
+ var old_html = formatDatalist(datalist);
+ if (safe_html != old_html) {
+ //console.log("HTML MISMATCH: ");
+ //console.log("FormatDatalistSafe: ");
+ // console.dir(root_div.get(0));
+ //console.log(safe_html);
+ //console.log("FormatDataList: ");
+ //console.log(old_html);
+ }
+ return root_div;
+ }
+ function formatDataSelection(datalist) {
+ // This a heinous workaround for a known bug in Select2.
+ // Without this, the rich selectlists are vulnerable to XSS.
+ // Many thanks to @uberbrady for this fix. It ain't pretty,
+ // but it resolves the issue until Select2 addresses it on their end.
+ //
+ // Bug was reported in 2016 :{
+ // https://github.com/select2/select2/issues/4587
+
+ return datalist.text.replace(/>/g, '>').replace(/Click me
+ $('a[data-toggle="tab"]').click(function (e) {
+ var href = $(this).attr("href");
+ history.pushState(null, null, href);
+ e.preventDefault();
+ $('a[href="' + $(this).attr('href') + '"]').tab('show');
+ });
+
+ // ------------------------------------------------
+ // End Deep Linking for Bootstrap tabs
+ // ------------------------------------------------
+
+ // Image preview
+ function readURL(input, $preview) {
+ if (input.files && input.files[0]) {
+ var reader = new FileReader();
+ reader.onload = function (e) {
+ $preview.attr('src', e.target.result);
+ };
+ reader.readAsDataURL(input.files[0]);
+ }
+ }
+ function formatBytes(bytes) {
+ if (bytes < 1024) return bytes + " Bytes";else if (bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB";else if (bytes < 1073741824) return (bytes / 1048576).toFixed(2) + " MB";else return (bytes / 1073741824).toFixed(2) + " GB";
+ }
+
+ // File size validation
+ $('.js-uploadFile').bind('change', function () {
+ var $this = $(this);
+ var id = '#' + $this.attr('id');
+ var status = id + '-status';
+ var $status = $(status);
+ var delete_id = $(id + '-deleteCheckbox');
+ var preview_container = $(id + '-previewContainer');
+ $status.removeClass('text-success').removeClass('text-danger');
+ $(status + ' .goodfile').remove();
+ $(status + ' .badfile').remove();
+ $(status + ' .previewSize').hide();
+ preview_container.hide();
+ $(id + '-info').html('');
+ var max_size = $this.data('maxsize');
+ var total_size = 0;
+ for (var i = 0; i < this.files.length; i++) {
+ total_size += this.files[i].size;
+ $(id + '-info').append('
' + htmlEntities(this.files[i].name) + ' (' + formatBytes(this.files[i].size) + ') ');
+ }
+ if (total_size > max_size) {
+ $status.addClass('text-danger').removeClass('help-block').prepend('
').append('
Upload is ' + formatBytes(total_size) + '.');
+ } else {
+ $status.addClass('text-success').removeClass('help-block').prepend('
');
+ var $preview = $(id + '-imagePreview');
+ readURL(this, $preview);
+ $preview.fadeIn();
+ preview_container.fadeIn();
+ delete_id.hide();
+ }
+ });
+});
+function htmlEntities(str) {
+ return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
+}
+
+/**
+ * Toggle disabled
+ */
+(function ($) {
+ $.fn.toggleDisabled = function (callback) {
+ return this.each(function () {
+ var disabled,
+ $this = $(this);
+ if ($this.attr('disabled')) {
+ $this.removeAttr('disabled');
+ disabled = false;
+ } else {
+ $this.attr('disabled', 'disabled');
+ disabled = true;
+ }
+ if (callback && typeof callback === 'function') {
+ callback(this, disabled);
+ }
+ });
+ };
+})(jQuery);
+
+/**
+ * Universal Livewire Select2 integration
+ *
+ * How to use:
+ *
+ * 1. Set the class of your select2 elements to 'livewire-select2').
+ * 2. Name your element to match a property in your Livewire component
+ * 3. Add an attribute called 'data-livewire-component' that points to $this->getId() (via `{{ }}` if you're in a blade,
+ * or just $this->getId() if not).
+ */
+document.addEventListener('livewire:init', function () {
+ $('.livewire-select2').select2();
+ $(document).on('select2:select', '.livewire-select2', function (event) {
+ var target = $(event.target);
+ if (!event.target.name || !target.data('livewire-component')) {
+ console.error("You need to set both name (which should match a Livewire property) and data-livewire-component on your Livewire-ed select2 elements!");
+ console.error("For data-livewire-component, you probably want to use $this->getId() or {{ $this->getId() }}, as appropriate");
+ return false;
+ }
+ Livewire.find(target.data('livewire-component')).set(event.target.name, this.options[this.selectedIndex].value);
+ });
+ Livewire.hook('request', function (_ref) {
+ var succeed = _ref.succeed;
+ succeed(function () {
+ queueMicrotask(function () {
+ $('.livewire-select2').select2();
+ });
+ });
+ });
+});
+
+/***/ }),
+
+/***/ "./resources/assets/js/snipeit_modals.js":
+/*!***********************************************!*\
+ !*** ./resources/assets/js/snipeit_modals.js ***!
+ \***********************************************/
+/***/ (() => {
+
+/*
+ *
+ * Snipe-IT Universal Modal support
+ *
+ * Enables modal dialogs to create sub-resources throughout Snipe-IT
+ *
+ */
+
+/*
+HOW TO USE
+ Create a Button looking like this:
+
New
+ If you don't have access to Blade commands (like {{ and }}, etc), you can hard-code a URL as the 'href'
+ data-toggle="modal" - required for Bootstrap Modals
+data-target="#createModal" - fixed ID for the modal, do not change
+data-select="assigned_to" - What is the *ID* of the select-dropdown that you're going to be adding to, if the modal-create was a success? Be on the lookout for duplicate ID's, it will confuse this library!
+class="btn btn-sm btn-primary" - makes it look button-ey, feel free to change :)
+
+If you want to pass additional variables to the modal (In the Category Create one, for example, you can pass category_id), you can encode them as URL variables in the href
+
+*/
+
+$(function () {
+ var baseUrl = $('meta[name="baseUrl"]').attr('content');
+ //handle modal-add-interstitial calls
+ var model, select, refreshSelector;
+ if ($('#createModal').length == 0) {
+ $('body').append('
');
+ }
+ $('#createModal').on("show.bs.modal", function (event) {
+ var link = $(event.relatedTarget);
+ model = link.data("dependency");
+ select = link.data("select");
+ refreshSelector = link.data("refresh");
+ $('#createModal').load(link.attr('href'), function () {
+ // this sets the focus to be the name field
+ $('#modal-name').focus();
+
+ //do we need to re-select2 this, after load? Probably.
+ $('#createModal').find('select.select2').select2();
+ // Initialize the ajaxy select2 with images.
+ // This is a copy/paste of the code from snipeit.js, would be great to only have this in one place.
+
+ $('.js-data-ajax').each(function (i, item) {
+ var link = $(item);
+ var endpoint = link.data("endpoint");
+ var select = link.data("select");
+ link.select2({
+ ajax: {
+ // the baseUrl includes a trailing slash
+ url: baseUrl + 'api/v1/' + endpoint + '/selectlist',
+ //WARNING - we're hoping that's defined on the page somewhere...
+ dataType: 'json',
+ delay: 250,
+ headers: {
+ "X-Requested-With": 'XMLHttpRequest',
+ "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
+ },
+ data: function data(params) {
+ var data = {
+ search: params.term,
+ page: params.page || 1,
+ assetStatusType: link.data("asset-status-type")
+ };
+ return data;
+ },
+ /*processResults: function (data, params) {
+ params.page = params.page || 1;
+ var answer = {
+ results: data.items,
+ pagination: {
+ more: data.pagination.more
+ }
+ };
+ return answer;
+ },*/
+ cache: true
+ },
+ //escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
+ templateResult: formatDatalistSafe
+ //templateSelection: formatDataSelection
+ });
+ });
+ });
+ });
+ $('#createModal').on('click', '#modal-save', function () {
+ $.ajax({
+ type: 'POST',
+ url: $('.modal-body form').attr('action'),
+ headers: {
+ "X-Requested-With": 'XMLHttpRequest',
+ "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
+ },
+ data: $('.modal-body form').serialize(),
+ success: function success(result) {
+ if (result.status == "error") {
+ var error_message = "";
+ for (var field in result.messages) {
+ error_message += "
Problem(s) with field " + field + ": " + result.messages[field];
+ }
+ $('#modal_error_msg').html(error_message).show();
+ return false;
+ }
+ var id = result.payload.id;
+ var name = result.payload.name || result.payload.first_name + " " + result.payload.last_name;
+ if (!id || !name) {
+ console.error("Could not find resulting name or ID from modal-create. Name: " + name + ", id: " + id);
+ return false;
+ }
+ $('#createModal').modal('hide');
+ $('#createModal').html("");
+ var refreshTable = $('#' + refreshSelector);
+ if (refreshTable.length > 0) {
+ refreshTable.bootstrapTable('refresh');
+ }
+
+ // "select" is the original drop-down menu that someone
+ // clicked 'add' on to add a new 'thing'
+ // this code adds the newly created object to that select
+ var selector = document.getElementById(select);
+ if (!selector) {
+ return false;
+ }
+ selector.options[selector.length] = new Option(name, id);
+ selector.selectedIndex = selector.length - 1;
+ $(selector).trigger("change");
+ if (window.fetchCustomFields) {
+ fetchCustomFields();
+ }
+ },
+ error: function error(result) {
+ msg = result.responseJSON.messages || result.responseJSON.error;
+ $('#modal_error_msg').html("Server Error: " + msg).show();
+ }
+ });
+ });
+});
+function formatDatalistSafe(datalist) {
+ // console.warn("What in the hell is going on with Select2?!?!!?!?");
+ // console.warn($.select2);
+ if (datalist.loading) {
+ return $(' Loading...');
+ }
+ var root_div = $("");
+ var left_pull = $("
");
+ if (datalist.image) {
+ var inner_div = $("
");
+ /******************************************************************
+ *
+ * We are specifically chosing empty alt-text below, because this
+ * image conveys no additional information, relative to the text
+ * that will *always* be there in any select2 list that is in use
+ * in Snipe-IT. If that changes, we would probably want to change
+ * some signatures of some functions, but right now, we don't want
+ * screen readers to say "HP SuperJet 5000, .... picture of HP
+ * SuperJet 5000..." and so on, for every single row in a list of
+ * assets or models or whatever.
+ *
+ *******************************************************************/
+ var img = $("
![]()
");
+ // console.warn("Img is: ");
+ // console.dir(img);
+ // console.warn("Strigularly, that's: ");
+ // console.log(img);
+ img.attr("src", datalist.image);
+ inner_div.append(img);
+ } else {
+ var inner_div = $("
");
+ }
+ left_pull.append(inner_div);
+ root_div.append(left_pull);
+ var name_div = $("
");
+ name_div.text(datalist.text);
+ root_div.append(name_div);
+ var safe_html = root_div.get(0).outerHTML;
+ var old_html = formatDatalist(datalist);
+ if (safe_html != old_html) {
+ // console.log("HTML MISMATCH: ");
+ // console.log("FormatDatalistSafe: ");
+ // console.dir(root_div.get(0));
+ // console.log(safe_html);
+ // console.log("FormatDataList: ");
+ // console.log(old_html);
+ }
+ return root_div;
+}
+function formatDatalist(datalist) {
+ var loading_markup = '
Loading...';
+ if (datalist.loading) {
+ return loading_markup;
+ }
+ var markup = "
";
+ markup += "
";
+ if (datalist.image) {
+ markup += "
";
+ } else {
+ markup += "
";
+ }
+ markup += "
" + datalist.text + "
";
+ markup += "
";
+ return markup;
+}
+function formatDataSelection(datalist) {
+ return datalist.text.replace(/>/g, '>').replace(/ {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "./resources/assets/less/overrides.less":
+/*!**********************************************!*\
+ !*** ./resources/assets/less/overrides.less ***!
+ \**********************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "./resources/assets/less/skins/_all-skins.less":
+/*!*****************************************************!*\
+ !*** ./resources/assets/less/skins/_all-skins.less ***!
+ \*****************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "./resources/assets/less/skins/skin-black-dark.less":
+/*!**********************************************************!*\
+ !*** ./resources/assets/less/skins/skin-black-dark.less ***!
+ \**********************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
/***/ }),
/***/ "./resources/assets/less/skins/skin-black.less":
@@ -33097,71 +33162,6 @@ __webpack_require__.r(__webpack_exports__);
// extracted by mini-css-extract-plugin
-/***/ }),
-
-/***/ "./node_modules/admin-lte/build/less/AdminLTE.less":
-/*!*********************************************************!*\
- !*** ./node_modules/admin-lte/build/less/AdminLTE.less ***!
- \*********************************************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-// extracted by mini-css-extract-plugin
-
-
-/***/ }),
-
-/***/ "./resources/assets/less/app.less":
-/*!****************************************!*\
- !*** ./resources/assets/less/app.less ***!
- \****************************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-// extracted by mini-css-extract-plugin
-
-
-/***/ }),
-
-/***/ "./resources/assets/less/overrides.less":
-/*!**********************************************!*\
- !*** ./resources/assets/less/overrides.less ***!
- \**********************************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-// extracted by mini-css-extract-plugin
-
-
-/***/ }),
-
-/***/ "./resources/assets/less/skins/_all-skins.less":
-/*!*****************************************************!*\
- !*** ./resources/assets/less/skins/_all-skins.less ***!
- \*****************************************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-// extracted by mini-css-extract-plugin
-
-
-/***/ }),
-
-/***/ "./resources/assets/less/skins/skin-black-dark.less":
-/*!**********************************************************!*\
- !*** ./resources/assets/less/skins/skin-black-dark.less ***!
- \**********************************************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-// extracted by mini-css-extract-plugin
-
-
/***/ })
/******/ });
diff --git a/public/js/dist/all.js b/public/js/dist/all.js
index f69d19394..b31634ca3 100644
--- a/public/js/dist/all.js
+++ b/public/js/dist/all.js
@@ -58934,799 +58934,16 @@ module.exports.TinyEmitter = E;
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
-/***/ "./resources/assets/js/bootstrap.js":
-/*!******************************************!*\
- !*** ./resources/assets/js/bootstrap.js ***!
- \******************************************/
-/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
+/***/ "./node_modules/admin-lte/build/less/AdminLTE.less":
+/*!*********************************************************!*\
+ !*** ./node_modules/admin-lte/build/less/AdminLTE.less ***!
+ \*********************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-window._ = __webpack_require__(/*! lodash */ "./node_modules/lodash/lodash.js");
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
-/**
- * We'll load jQuery and the Bootstrap jQuery plugin which provides support
- * for JavaScript based Bootstrap features such as modals and tabs. This
- * code may be modified to fit the specific needs of your application.
- */
-//window.$ = window.jQuery = require('jquery');
-
-/**
- * jQuery UI is loaded here and then the tooltip is assigned another funtion name
- * This resolves the issue of jquery-ui & bootstrap tooltip conflict
- */
-__webpack_require__(/*! jquery-ui */ "./node_modules/jquery-ui/ui/widget.js");
-jQuery.fn.uitooltip = jQuery.fn.tooltip;
-
-/**
- * Load boostrap
- */
-__webpack_require__(/*! bootstrap-less */ "./node_modules/bootstrap-less/js/bootstrap.js");
-
-// require('admin-lte');
-
-// require('chart.js');
-
-// require('jquery-form-validator'); //says something about dependency
-/**
- * Echo exposes an expressive API for subscribing to channels and listening
- * for events that are broadcast by Laravel. Echo and event broadcasting
- * allows your team to easily build robust real-time web applications.
- */
-
-// import Echo from "laravel-echo"
-
-// window.Echo = new Echo({
-// broadcaster: 'pusher',
-// key: 'your-pusher-key'
-// });
-
-/***/ }),
-
-/***/ "./resources/assets/js/snipeit.js":
-/*!****************************************!*\
- !*** ./resources/assets/js/snipeit.js ***!
- \****************************************/
-/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
-
-// var jQuery = require('jquery');
-// window.jQuery = jQuery
-// window.$ = jQuery
-
-__webpack_require__(/*! ./bootstrap */ "./resources/assets/js/bootstrap.js");
-
-/**
- * Module containing core application logic.
- * @param {jQuery} $ Insulated jQuery object
- * @param {JSON} settings Insulated `window.snipeit.settings` object.
- * @return {IIFE} Immediately invoked. Returns self.
- */
-
-lineOptions = {
- legend: {
- position: "bottom"
- },
- scales: {
- yAxes: [{
- ticks: {
- fontColor: "rgba(0,0,0,0.5)",
- fontStyle: "bold",
- beginAtZero: true,
- maxTicksLimit: 5,
- padding: 20
- },
- gridLines: {
- drawTicks: false,
- display: false
- }
- }],
- xAxes: [{
- gridLines: {
- zeroLineColor: "transparent"
- },
- ticks: {
- padding: 20,
- fontColor: "rgba(0,0,0,0.5)",
- fontStyle: "bold"
- }
- }]
- }
-};
-pieOptions = {
- //Boolean - Whether we should show a stroke on each segment
- segmentShowStroke: true,
- //String - The colour of each segment stroke
- segmentStrokeColor: "#fff",
- //Number - The width of each segment stroke
- segmentStrokeWidth: 1,
- //Number - The percentage of the chart that we cut out of the middle
- percentageInnerCutout: 50,
- // This is 0 for Pie charts
- //Number - Amount of animation steps
- animationSteps: 100,
- //String - Animation easing effect
- animationEasing: "easeOutBounce",
- //Boolean - Whether we animate the rotation of the Doughnut
- animateRotate: true,
- //Boolean - Whether we animate scaling the Doughnut from the centre
- animateScale: false,
- //Boolean - whether to make the chart responsive to window resizing
- responsive: true,
- // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
- maintainAspectRatio: false,
- //String - A legend template
- legendTemplate: "
-legend\"><% for (var i=0; i- " + "" + "<%if(segments[i].label){%><%=segments[i].label%><%}%> foo
<%}%>
",
- //String - A tooltip template
- tooltipTemplate: "<%=value %> <%=label%> "
-};
-
-//-----------------
-//- END PIE CHART -
-//-----------------
-
-var baseUrl = $('meta[name="baseUrl"]').attr('content');
-$(function () {
- var $el = $('table');
-
- // confirm restore modal
-
- $el.on('click', '.restore-asset', function (evnt) {
- var $context = $(this);
- var $restoreConfirmModal = $('#restoreConfirmModal');
- var href = $context.attr('href');
- var message = $context.attr('data-content');
- var title = $context.attr('data-title');
- $('#confirmModalLabel').text(title);
- $restoreConfirmModal.find('.modal-body').text(message);
- $('#restoreForm').attr('action', href);
- $restoreConfirmModal.modal({
- show: true
- });
- return false;
- });
-
- // confirm delete modal
-
- $el.on('click', '.delete-asset', function (evnt) {
- var $context = $(this);
- var $dataConfirmModal = $('#dataConfirmModal');
- var href = $context.attr('href');
- var message = $context.attr('data-content');
- var title = $context.attr('data-title');
- $('#myModalLabel').text(title);
- $dataConfirmModal.find('.modal-body').text(message);
- $('#deleteForm').attr('action', href);
- $dataConfirmModal.modal({
- show: true
- });
- return false;
- });
-
- /*
- * Slideout help menu
- */
- $('.slideout-menu-toggle').on('click', function (event) {
- event.preventDefault();
- // create menu variables
- var slideoutMenu = $('.slideout-menu');
- var slideoutMenuWidth = $('.slideout-menu').width();
-
- // toggle open class
- slideoutMenu.toggleClass("open");
-
- // slide menu
- if (slideoutMenu.hasClass("open")) {
- slideoutMenu.show();
- slideoutMenu.animate({
- right: "0px"
- });
- } else {
- slideoutMenu.animate({
- right: -slideoutMenuWidth
- }, "-350px");
- slideoutMenu.fadeOut();
- }
- });
-
- /*
- * Select2
- */
-
- $('select.select2:not(".select2-hidden-accessible")').each(function (i, obj) {
- {
- $(obj).select2();
- }
- });
-
- // $('.datepicker').datepicker();
- // var datepicker = $.fn.datepicker.noConflict(); // return $.fn.datepicker to previously assigned value
- // $.fn.bootstrapDP = datepicker;
- // $('.datepicker').datepicker();
-
- // Crazy select2 rich dropdowns with images!
- $('.js-data-ajax').each(function (i, item) {
- var link = $(item);
- var endpoint = link.data("endpoint");
- var select = link.data("select");
- link.select2({
- /**
- * Adds an empty placeholder, allowing every select2 instance to be cleared.
- * This placeholder can be overridden with the "data-placeholder" attribute.
- */
- placeholder: '',
- allowClear: true,
- language: $('meta[name="language"]').attr('content'),
- dir: $('meta[name="language-direction"]').attr('content'),
- ajax: {
- // the baseUrl includes a trailing slash
- url: baseUrl + 'api/v1/' + endpoint + '/selectlist',
- dataType: 'json',
- delay: 250,
- headers: {
- "X-Requested-With": 'XMLHttpRequest',
- "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
- },
- data: function data(params) {
- var data = {
- search: params.term,
- page: params.page || 1,
- assetStatusType: link.data("asset-status-type")
- };
- return data;
- },
- /* processResults: function (data, params) {
- params.page = params.page || 1;
- var answer = {
- results: data.items,
- pagination: {
- more: data.pagination.more
- }
- };
- return answer;
- }, */
- cache: true
- },
- //escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
- templateResult: formatDatalistSafe
- //templateSelection: formatDataSelection
- });
- });
- function getSelect2Value(element) {
- // if the passed object is not a jquery object, assuming 'element' is a selector
- if (!(element instanceof jQuery)) element = $(element);
- var select = element.data("select2");
-
- // There's two different locations where the select2-generated input element can be.
- searchElement = select.dropdown.$search || select.$container.find(".select2-search__field");
- var value = searchElement.val();
- return value;
- }
- $(".select2-hidden-accessible").on('select2:selecting', function (e) {
- var data = e.params.args.data;
- var isMouseUp = false;
- var element = $(this);
- var value = getSelect2Value(element);
- if (e.params.args.originalEvent) isMouseUp = e.params.args.originalEvent.type == "mouseup";
-
- // if selected item does not match typed text, do not allow it to pass - force close for ajax.
- if (!isMouseUp) {
- if (value.toLowerCase() && data.text.toLowerCase().indexOf(value) < 0) {
- e.preventDefault();
- element.select2('close');
-
- // if it does match, we set a flag in the event (which gets passed to subsequent events), telling it not to worry about the ajax
- } else if (value.toLowerCase() && data.text.toLowerCase().indexOf(value) > -1) {
- e.params.args.noForceAjax = true;
- }
- }
- });
- $(".select2-hidden-accessible").on('select2:closing', function (e) {
- var element = $(this);
- var value = getSelect2Value(element);
- var noForceAjax = false;
- var isMouseUp = false;
- if (e.params.args.originalSelect2Event) noForceAjax = e.params.args.originalSelect2Event.noForceAjax;
- if (e.params.args.originalEvent) isMouseUp = e.params.args.originalEvent.type == "mouseup";
- if (value && !noForceAjax && !isMouseUp) {
- var endpoint = element.data("endpoint");
- var assetStatusType = element.data("asset-status-type");
- $.ajax({
- url: baseUrl + 'api/v1/' + endpoint + '/selectlist?search=' + value + '&page=1' + (assetStatusType ? '&assetStatusType=' + assetStatusType : ''),
- dataType: 'json',
- headers: {
- "X-Requested-With": 'XMLHttpRequest',
- "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
- }
- }).done(function (response) {
- var currentlySelected = element.select2('data').map(function (x) {
- return +x.id;
- }).filter(function (x) {
- return x !== 0;
- });
-
- // makes sure we're not selecting the same thing twice for multiples
- var filteredResponse = response.results.filter(function (item) {
- return currentlySelected.indexOf(+item.id) < 0;
- });
- var first = currentlySelected.length > 0 ? filteredResponse[0] : response.results[0];
- if (first && first.id) {
- first.selected = true;
- if ($("option[value='" + first.id + "']", element).length < 1) {
- var option = new Option(first.text, first.id, true, true);
- element.append(option);
- } else {
- var isMultiple = element.attr("multiple") == "multiple";
- element.val(isMultiple ? element.val().concat(first.id) : element.val(first.id));
- }
- element.trigger('change');
- element.trigger({
- type: 'select2:select',
- params: {
- data: first
- }
- });
- }
- });
- }
- });
- function formatDatalist(datalist) {
- var loading_markup = '
Loading...';
- if (datalist.loading) {
- return loading_markup;
- }
- var markup = '
';
- markup += '
';
- if (datalist.image) {
- markup += "
";
- } else {
- markup += '
';
- }
- markup += "
" + datalist.text + "
";
- markup += "
";
- return markup;
- }
- function formatDatalistSafe(datalist) {
- // console.warn("What in the hell is going on with Select2?!?!!?!?");
- // console.warn($.select2);
- if (datalist.loading) {
- return $('
Loading...');
- }
- var root_div = $("
");
- var left_pull = $("
");
- if (datalist.image) {
- var inner_div = $("
");
- /******************************************************************
- *
- * We are specifically chosing empty alt-text below, because this
- * image conveys no additional information, relative to the text
- * that will *always* be there in any select2 list that is in use
- * in Snipe-IT. If that changes, we would probably want to change
- * some signatures of some functions, but right now, we don't want
- * screen readers to say "HP SuperJet 5000, .... picture of HP
- * SuperJet 5000..." and so on, for every single row in a list of
- * assets or models or whatever.
- *
- *******************************************************************/
- var img = $("
![]()
");
- // console.warn("Img is: ");
- // console.dir(img);
- // console.warn("Strigularly, that's: ");
- // console.log(img);
- img.attr("src", datalist.image);
- inner_div.append(img);
- } else {
- var inner_div = $("
");
- }
- left_pull.append(inner_div);
- root_div.append(left_pull);
- var name_div = $("
");
- name_div.text(datalist.text);
- root_div.append(name_div);
- var safe_html = root_div.get(0).outerHTML;
- var old_html = formatDatalist(datalist);
- if (safe_html != old_html) {
- //console.log("HTML MISMATCH: ");
- //console.log("FormatDatalistSafe: ");
- // console.dir(root_div.get(0));
- //console.log(safe_html);
- //console.log("FormatDataList: ");
- //console.log(old_html);
- }
- return root_div;
- }
- function formatDataSelection(datalist) {
- // This a heinous workaround for a known bug in Select2.
- // Without this, the rich selectlists are vulnerable to XSS.
- // Many thanks to @uberbrady for this fix. It ain't pretty,
- // but it resolves the issue until Select2 addresses it on their end.
- //
- // Bug was reported in 2016 :{
- // https://github.com/select2/select2/issues/4587
-
- return datalist.text.replace(/>/g, '>').replace(/Click me
- $('a[data-toggle="tab"]').click(function (e) {
- var href = $(this).attr("href");
- history.pushState(null, null, href);
- e.preventDefault();
- $('a[href="' + $(this).attr('href') + '"]').tab('show');
- });
-
- // ------------------------------------------------
- // End Deep Linking for Bootstrap tabs
- // ------------------------------------------------
-
- // Image preview
- function readURL(input, $preview) {
- if (input.files && input.files[0]) {
- var reader = new FileReader();
- reader.onload = function (e) {
- $preview.attr('src', e.target.result);
- };
- reader.readAsDataURL(input.files[0]);
- }
- }
- function formatBytes(bytes) {
- if (bytes < 1024) return bytes + " Bytes";else if (bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB";else if (bytes < 1073741824) return (bytes / 1048576).toFixed(2) + " MB";else return (bytes / 1073741824).toFixed(2) + " GB";
- }
-
- // File size validation
- $('.js-uploadFile').bind('change', function () {
- var $this = $(this);
- var id = '#' + $this.attr('id');
- var status = id + '-status';
- var $status = $(status);
- var delete_id = $(id + '-deleteCheckbox');
- var preview_container = $(id + '-previewContainer');
- $status.removeClass('text-success').removeClass('text-danger');
- $(status + ' .goodfile').remove();
- $(status + ' .badfile').remove();
- $(status + ' .previewSize').hide();
- preview_container.hide();
- $(id + '-info').html('');
- var max_size = $this.data('maxsize');
- var total_size = 0;
- for (var i = 0; i < this.files.length; i++) {
- total_size += this.files[i].size;
- $(id + '-info').append('
' + htmlEntities(this.files[i].name) + ' (' + formatBytes(this.files[i].size) + ') ');
- }
- if (total_size > max_size) {
- $status.addClass('text-danger').removeClass('help-block').prepend('
').append('
Upload is ' + formatBytes(total_size) + '.');
- } else {
- $status.addClass('text-success').removeClass('help-block').prepend('
');
- var $preview = $(id + '-imagePreview');
- readURL(this, $preview);
- $preview.fadeIn();
- preview_container.fadeIn();
- delete_id.hide();
- }
- });
-});
-function htmlEntities(str) {
- return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
-}
-
-/**
- * Toggle disabled
- */
-(function ($) {
- $.fn.toggleDisabled = function (callback) {
- return this.each(function () {
- var disabled,
- $this = $(this);
- if ($this.attr('disabled')) {
- $this.removeAttr('disabled');
- disabled = false;
- } else {
- $this.attr('disabled', 'disabled');
- disabled = true;
- }
- if (callback && typeof callback === 'function') {
- callback(this, disabled);
- }
- });
- };
-})(jQuery);
-
-/**
- * Universal Livewire Select2 integration
- *
- * How to use:
- *
- * 1. Set the class of your select2 elements to 'livewire-select2').
- * 2. Name your element to match a property in your Livewire component
- * 3. Add an attribute called 'data-livewire-component' that points to $this->getId() (via `{{ }}` if you're in a blade,
- * or just $this->getId() if not).
- */
-document.addEventListener('livewire:init', function () {
- $('.livewire-select2').select2();
- $(document).on('select2:select', '.livewire-select2', function (event) {
- var target = $(event.target);
- if (!event.target.name || !target.data('livewire-component')) {
- console.error("You need to set both name (which should match a Livewire property) and data-livewire-component on your Livewire-ed select2 elements!");
- console.error("For data-livewire-component, you probably want to use $this->getId() or {{ $this->getId() }}, as appropriate");
- return false;
- }
- Livewire.find(target.data('livewire-component')).set(event.target.name, this.options[this.selectedIndex].value);
- });
- Livewire.hook('request', function (_ref) {
- var succeed = _ref.succeed;
- succeed(function () {
- queueMicrotask(function () {
- $('.livewire-select2').select2();
- });
- });
- });
-});
-
-/***/ }),
-
-/***/ "./resources/assets/js/snipeit_modals.js":
-/*!***********************************************!*\
- !*** ./resources/assets/js/snipeit_modals.js ***!
- \***********************************************/
-/***/ (() => {
-
-/*
- *
- * Snipe-IT Universal Modal support
- *
- * Enables modal dialogs to create sub-resources throughout Snipe-IT
- *
- */
-
-/*
-HOW TO USE
- Create a Button looking like this:
-
New
- If you don't have access to Blade commands (like {{ and }}, etc), you can hard-code a URL as the 'href'
- data-toggle="modal" - required for Bootstrap Modals
-data-target="#createModal" - fixed ID for the modal, do not change
-data-select="assigned_to" - What is the *ID* of the select-dropdown that you're going to be adding to, if the modal-create was a success? Be on the lookout for duplicate ID's, it will confuse this library!
-class="btn btn-sm btn-primary" - makes it look button-ey, feel free to change :)
-
-If you want to pass additional variables to the modal (In the Category Create one, for example, you can pass category_id), you can encode them as URL variables in the href
-
-*/
-
-$(function () {
- var baseUrl = $('meta[name="baseUrl"]').attr('content');
- //handle modal-add-interstitial calls
- var model, select, refreshSelector;
- if ($('#createModal').length == 0) {
- $('body').append('
');
- }
- $('#createModal').on("show.bs.modal", function (event) {
- var link = $(event.relatedTarget);
- model = link.data("dependency");
- select = link.data("select");
- refreshSelector = link.data("refresh");
- $('#createModal').load(link.attr('href'), function () {
- // this sets the focus to be the name field
- $('#modal-name').focus();
-
- //do we need to re-select2 this, after load? Probably.
- $('#createModal').find('select.select2').select2();
- // Initialize the ajaxy select2 with images.
- // This is a copy/paste of the code from snipeit.js, would be great to only have this in one place.
-
- $('.js-data-ajax').each(function (i, item) {
- var link = $(item);
- var endpoint = link.data("endpoint");
- var select = link.data("select");
- link.select2({
- ajax: {
- // the baseUrl includes a trailing slash
- url: baseUrl + 'api/v1/' + endpoint + '/selectlist',
- //WARNING - we're hoping that's defined on the page somewhere...
- dataType: 'json',
- delay: 250,
- headers: {
- "X-Requested-With": 'XMLHttpRequest',
- "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
- },
- data: function data(params) {
- var data = {
- search: params.term,
- page: params.page || 1,
- assetStatusType: link.data("asset-status-type")
- };
- return data;
- },
- /*processResults: function (data, params) {
- params.page = params.page || 1;
- var answer = {
- results: data.items,
- pagination: {
- more: data.pagination.more
- }
- };
- return answer;
- },*/
- cache: true
- },
- //escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
- templateResult: formatDatalistSafe
- //templateSelection: formatDataSelection
- });
- });
- });
- });
- $('#createModal').on('click', '#modal-save', function () {
- $.ajax({
- type: 'POST',
- url: $('.modal-body form').attr('action'),
- headers: {
- "X-Requested-With": 'XMLHttpRequest',
- "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
- },
- data: $('.modal-body form').serialize(),
- success: function success(result) {
- if (result.status == "error") {
- var error_message = "";
- for (var field in result.messages) {
- error_message += "
Problem(s) with field " + field + ": " + result.messages[field];
- }
- $('#modal_error_msg').html(error_message).show();
- return false;
- }
- var id = result.payload.id;
- var name = result.payload.name || result.payload.first_name + " " + result.payload.last_name;
- if (!id || !name) {
- console.error("Could not find resulting name or ID from modal-create. Name: " + name + ", id: " + id);
- return false;
- }
- $('#createModal').modal('hide');
- $('#createModal').html("");
- var refreshTable = $('#' + refreshSelector);
- if (refreshTable.length > 0) {
- refreshTable.bootstrapTable('refresh');
- }
-
- // "select" is the original drop-down menu that someone
- // clicked 'add' on to add a new 'thing'
- // this code adds the newly created object to that select
- var selector = document.getElementById(select);
- if (!selector) {
- return false;
- }
- selector.options[selector.length] = new Option(name, id);
- selector.selectedIndex = selector.length - 1;
- $(selector).trigger("change");
- if (window.fetchCustomFields) {
- fetchCustomFields();
- }
- },
- error: function error(result) {
- msg = result.responseJSON.messages || result.responseJSON.error;
- $('#modal_error_msg').html("Server Error: " + msg).show();
- }
- });
- });
-});
-function formatDatalistSafe(datalist) {
- // console.warn("What in the hell is going on with Select2?!?!!?!?");
- // console.warn($.select2);
- if (datalist.loading) {
- return $(' Loading...');
- }
- var root_div = $("");
- var left_pull = $("
");
- if (datalist.image) {
- var inner_div = $("
");
- /******************************************************************
- *
- * We are specifically chosing empty alt-text below, because this
- * image conveys no additional information, relative to the text
- * that will *always* be there in any select2 list that is in use
- * in Snipe-IT. If that changes, we would probably want to change
- * some signatures of some functions, but right now, we don't want
- * screen readers to say "HP SuperJet 5000, .... picture of HP
- * SuperJet 5000..." and so on, for every single row in a list of
- * assets or models or whatever.
- *
- *******************************************************************/
- var img = $("
![]()
");
- // console.warn("Img is: ");
- // console.dir(img);
- // console.warn("Strigularly, that's: ");
- // console.log(img);
- img.attr("src", datalist.image);
- inner_div.append(img);
- } else {
- var inner_div = $("
");
- }
- left_pull.append(inner_div);
- root_div.append(left_pull);
- var name_div = $("
");
- name_div.text(datalist.text);
- root_div.append(name_div);
- var safe_html = root_div.get(0).outerHTML;
- var old_html = formatDatalist(datalist);
- if (safe_html != old_html) {
- // console.log("HTML MISMATCH: ");
- // console.log("FormatDatalistSafe: ");
- // console.dir(root_div.get(0));
- // console.log(safe_html);
- // console.log("FormatDataList: ");
- // console.log(old_html);
- }
- return root_div;
-}
-function formatDatalist(datalist) {
- var loading_markup = '
Loading...';
- if (datalist.loading) {
- return loading_markup;
- }
- var markup = "
";
- markup += "
";
- if (datalist.image) {
- markup += "
";
- } else {
- markup += "
";
- }
- markup += "
" + datalist.text + "
";
- markup += "
";
- return markup;
-}
-function formatDataSelection(datalist) {
- return datalist.text.replace(/>/g, '>').replace(/ {
+
+window._ = __webpack_require__(/*! lodash */ "./node_modules/lodash/lodash.js");
+
+/**
+ * We'll load jQuery and the Bootstrap jQuery plugin which provides support
+ * for JavaScript based Bootstrap features such as modals and tabs. This
+ * code may be modified to fit the specific needs of your application.
+ */
+//window.$ = window.jQuery = require('jquery');
+
+/**
+ * jQuery UI is loaded here and then the tooltip is assigned another funtion name
+ * This resolves the issue of jquery-ui & bootstrap tooltip conflict
+ */
+__webpack_require__(/*! jquery-ui */ "./node_modules/jquery-ui/ui/widget.js");
+jQuery.fn.uitooltip = jQuery.fn.tooltip;
+
+/**
+ * Load boostrap
+ */
+__webpack_require__(/*! bootstrap-less */ "./node_modules/bootstrap-less/js/bootstrap.js");
+
+// require('admin-lte');
+
+// require('chart.js');
+
+// require('jquery-form-validator'); //says something about dependency
+/**
+ * Echo exposes an expressive API for subscribing to channels and listening
+ * for events that are broadcast by Laravel. Echo and event broadcasting
+ * allows your team to easily build robust real-time web applications.
+ */
+
+// import Echo from "laravel-echo"
+
+// window.Echo = new Echo({
+// broadcaster: 'pusher',
+// key: 'your-pusher-key'
+// });
+
+/***/ }),
+
+/***/ "./resources/assets/js/snipeit.js":
+/*!****************************************!*\
+ !*** ./resources/assets/js/snipeit.js ***!
+ \****************************************/
+/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
+
+// var jQuery = require('jquery');
+// window.jQuery = jQuery
+// window.$ = jQuery
+
+__webpack_require__(/*! ./bootstrap */ "./resources/assets/js/bootstrap.js");
+
+/**
+ * Module containing core application logic.
+ * @param {jQuery} $ Insulated jQuery object
+ * @param {JSON} settings Insulated `window.snipeit.settings` object.
+ * @return {IIFE} Immediately invoked. Returns self.
+ */
+
+lineOptions = {
+ legend: {
+ position: "bottom"
+ },
+ scales: {
+ yAxes: [{
+ ticks: {
+ fontColor: "rgba(0,0,0,0.5)",
+ fontStyle: "bold",
+ beginAtZero: true,
+ maxTicksLimit: 5,
+ padding: 20
+ },
+ gridLines: {
+ drawTicks: false,
+ display: false
+ }
+ }],
+ xAxes: [{
+ gridLines: {
+ zeroLineColor: "transparent"
+ },
+ ticks: {
+ padding: 20,
+ fontColor: "rgba(0,0,0,0.5)",
+ fontStyle: "bold"
+ }
+ }]
+ }
+};
+pieOptions = {
+ //Boolean - Whether we should show a stroke on each segment
+ segmentShowStroke: true,
+ //String - The colour of each segment stroke
+ segmentStrokeColor: "#fff",
+ //Number - The width of each segment stroke
+ segmentStrokeWidth: 1,
+ //Number - The percentage of the chart that we cut out of the middle
+ percentageInnerCutout: 50,
+ // This is 0 for Pie charts
+ //Number - Amount of animation steps
+ animationSteps: 100,
+ //String - Animation easing effect
+ animationEasing: "easeOutBounce",
+ //Boolean - Whether we animate the rotation of the Doughnut
+ animateRotate: true,
+ //Boolean - Whether we animate scaling the Doughnut from the centre
+ animateScale: false,
+ //Boolean - whether to make the chart responsive to window resizing
+ responsive: true,
+ // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
+ maintainAspectRatio: false,
+ //String - A legend template
+ legendTemplate: "
-legend\"><% for (var i=0; i- " + "" + "<%if(segments[i].label){%><%=segments[i].label%><%}%> foo
<%}%>
",
+ //String - A tooltip template
+ tooltipTemplate: "<%=value %> <%=label%> "
+};
+
+//-----------------
+//- END PIE CHART -
+//-----------------
+
+var baseUrl = $('meta[name="baseUrl"]').attr('content');
+$(function () {
+ var $el = $('table');
+
+ // confirm restore modal
+
+ $el.on('click', '.restore-asset', function (evnt) {
+ var $context = $(this);
+ var $restoreConfirmModal = $('#restoreConfirmModal');
+ var href = $context.attr('href');
+ var message = $context.attr('data-content');
+ var title = $context.attr('data-title');
+ $('#confirmModalLabel').text(title);
+ $restoreConfirmModal.find('.modal-body').text(message);
+ $('#restoreForm').attr('action', href);
+ $restoreConfirmModal.modal({
+ show: true
+ });
+ return false;
+ });
+
+ // confirm delete modal
+
+ $el.on('click', '.delete-asset', function (evnt) {
+ var $context = $(this);
+ var $dataConfirmModal = $('#dataConfirmModal');
+ var href = $context.attr('href');
+ var message = $context.attr('data-content');
+ var title = $context.attr('data-title');
+ $('#myModalLabel').text(title);
+ $dataConfirmModal.find('.modal-body').text(message);
+ $('#deleteForm').attr('action', href);
+ $dataConfirmModal.modal({
+ show: true
+ });
+ return false;
+ });
+
+ /*
+ * Slideout help menu
+ */
+ $('.slideout-menu-toggle').on('click', function (event) {
+ event.preventDefault();
+ // create menu variables
+ var slideoutMenu = $('.slideout-menu');
+ var slideoutMenuWidth = $('.slideout-menu').width();
+
+ // toggle open class
+ slideoutMenu.toggleClass("open");
+
+ // slide menu
+ if (slideoutMenu.hasClass("open")) {
+ slideoutMenu.show();
+ slideoutMenu.animate({
+ right: "0px"
+ });
+ } else {
+ slideoutMenu.animate({
+ right: -slideoutMenuWidth
+ }, "-350px");
+ slideoutMenu.fadeOut();
+ }
+ });
+
+ /*
+ * Select2
+ */
+
+ $('select.select2:not(".select2-hidden-accessible")').each(function (i, obj) {
+ {
+ $(obj).select2();
+ }
+ });
+
+ // $('.datepicker').datepicker();
+ // var datepicker = $.fn.datepicker.noConflict(); // return $.fn.datepicker to previously assigned value
+ // $.fn.bootstrapDP = datepicker;
+ // $('.datepicker').datepicker();
+
+ // Crazy select2 rich dropdowns with images!
+ $('.js-data-ajax').each(function (i, item) {
+ var link = $(item);
+ var endpoint = link.data("endpoint");
+ var select = link.data("select");
+ link.select2({
+ /**
+ * Adds an empty placeholder, allowing every select2 instance to be cleared.
+ * This placeholder can be overridden with the "data-placeholder" attribute.
+ */
+ placeholder: '',
+ allowClear: true,
+ language: $('meta[name="language"]').attr('content'),
+ dir: $('meta[name="language-direction"]').attr('content'),
+ ajax: {
+ // the baseUrl includes a trailing slash
+ url: baseUrl + 'api/v1/' + endpoint + '/selectlist',
+ dataType: 'json',
+ delay: 250,
+ headers: {
+ "X-Requested-With": 'XMLHttpRequest',
+ "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
+ },
+ data: function data(params) {
+ var data = {
+ search: params.term,
+ page: params.page || 1,
+ assetStatusType: link.data("asset-status-type")
+ };
+ return data;
+ },
+ /* processResults: function (data, params) {
+ params.page = params.page || 1;
+ var answer = {
+ results: data.items,
+ pagination: {
+ more: data.pagination.more
+ }
+ };
+ return answer;
+ }, */
+ cache: true
+ },
+ //escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
+ templateResult: formatDatalistSafe
+ //templateSelection: formatDataSelection
+ });
+ });
+ function getSelect2Value(element) {
+ // if the passed object is not a jquery object, assuming 'element' is a selector
+ if (!(element instanceof jQuery)) element = $(element);
+ var select = element.data("select2");
+
+ // There's two different locations where the select2-generated input element can be.
+ searchElement = select.dropdown.$search || select.$container.find(".select2-search__field");
+ var value = searchElement.val();
+ return value;
+ }
+ $(".select2-hidden-accessible").on('select2:selecting', function (e) {
+ var data = e.params.args.data;
+ var isMouseUp = false;
+ var element = $(this);
+ var value = getSelect2Value(element);
+ if (e.params.args.originalEvent) isMouseUp = e.params.args.originalEvent.type == "mouseup";
+
+ // if selected item does not match typed text, do not allow it to pass - force close for ajax.
+ if (!isMouseUp) {
+ if (value.toLowerCase() && data.text.toLowerCase().indexOf(value) < 0) {
+ e.preventDefault();
+ element.select2('close');
+
+ // if it does match, we set a flag in the event (which gets passed to subsequent events), telling it not to worry about the ajax
+ } else if (value.toLowerCase() && data.text.toLowerCase().indexOf(value) > -1) {
+ e.params.args.noForceAjax = true;
+ }
+ }
+ });
+ $(".select2-hidden-accessible").on('select2:closing', function (e) {
+ var element = $(this);
+ var value = getSelect2Value(element);
+ var noForceAjax = false;
+ var isMouseUp = false;
+ if (e.params.args.originalSelect2Event) noForceAjax = e.params.args.originalSelect2Event.noForceAjax;
+ if (e.params.args.originalEvent) isMouseUp = e.params.args.originalEvent.type == "mouseup";
+ if (value && !noForceAjax && !isMouseUp) {
+ var endpoint = element.data("endpoint");
+ var assetStatusType = element.data("asset-status-type");
+ $.ajax({
+ url: baseUrl + 'api/v1/' + endpoint + '/selectlist?search=' + value + '&page=1' + (assetStatusType ? '&assetStatusType=' + assetStatusType : ''),
+ dataType: 'json',
+ headers: {
+ "X-Requested-With": 'XMLHttpRequest',
+ "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
+ }
+ }).done(function (response) {
+ var currentlySelected = element.select2('data').map(function (x) {
+ return +x.id;
+ }).filter(function (x) {
+ return x !== 0;
+ });
+
+ // makes sure we're not selecting the same thing twice for multiples
+ var filteredResponse = response.results.filter(function (item) {
+ return currentlySelected.indexOf(+item.id) < 0;
+ });
+ var first = currentlySelected.length > 0 ? filteredResponse[0] : response.results[0];
+ if (first && first.id) {
+ first.selected = true;
+ if ($("option[value='" + first.id + "']", element).length < 1) {
+ var option = new Option(first.text, first.id, true, true);
+ element.append(option);
+ } else {
+ var isMultiple = element.attr("multiple") == "multiple";
+ element.val(isMultiple ? element.val().concat(first.id) : element.val(first.id));
+ }
+ element.trigger('change');
+ element.trigger({
+ type: 'select2:select',
+ params: {
+ data: first
+ }
+ });
+ }
+ });
+ }
+ });
+ function formatDatalist(datalist) {
+ var loading_markup = '
Loading...';
+ if (datalist.loading) {
+ return loading_markup;
+ }
+ var markup = '
';
+ markup += '
';
+ if (datalist.image) {
+ markup += "
";
+ } else {
+ markup += '
';
+ }
+ markup += "
" + datalist.text + "
";
+ markup += "
";
+ return markup;
+ }
+ function formatDatalistSafe(datalist) {
+ // console.warn("What in the hell is going on with Select2?!?!!?!?");
+ // console.warn($.select2);
+ if (datalist.loading) {
+ return $('
Loading...');
+ }
+ var root_div = $("
");
+ var left_pull = $("
");
+ if (datalist.image) {
+ var inner_div = $("
");
+ /******************************************************************
+ *
+ * We are specifically chosing empty alt-text below, because this
+ * image conveys no additional information, relative to the text
+ * that will *always* be there in any select2 list that is in use
+ * in Snipe-IT. If that changes, we would probably want to change
+ * some signatures of some functions, but right now, we don't want
+ * screen readers to say "HP SuperJet 5000, .... picture of HP
+ * SuperJet 5000..." and so on, for every single row in a list of
+ * assets or models or whatever.
+ *
+ *******************************************************************/
+ var img = $("
![]()
");
+ // console.warn("Img is: ");
+ // console.dir(img);
+ // console.warn("Strigularly, that's: ");
+ // console.log(img);
+ img.attr("src", datalist.image);
+ inner_div.append(img);
+ } else {
+ var inner_div = $("
");
+ }
+ left_pull.append(inner_div);
+ root_div.append(left_pull);
+ var name_div = $("
");
+ name_div.text(datalist.text);
+ root_div.append(name_div);
+ var safe_html = root_div.get(0).outerHTML;
+ var old_html = formatDatalist(datalist);
+ if (safe_html != old_html) {
+ //console.log("HTML MISMATCH: ");
+ //console.log("FormatDatalistSafe: ");
+ // console.dir(root_div.get(0));
+ //console.log(safe_html);
+ //console.log("FormatDataList: ");
+ //console.log(old_html);
+ }
+ return root_div;
+ }
+ function formatDataSelection(datalist) {
+ // This a heinous workaround for a known bug in Select2.
+ // Without this, the rich selectlists are vulnerable to XSS.
+ // Many thanks to @uberbrady for this fix. It ain't pretty,
+ // but it resolves the issue until Select2 addresses it on their end.
+ //
+ // Bug was reported in 2016 :{
+ // https://github.com/select2/select2/issues/4587
+
+ return datalist.text.replace(/>/g, '>').replace(/Click me
+ $('a[data-toggle="tab"]').click(function (e) {
+ var href = $(this).attr("href");
+ history.pushState(null, null, href);
+ e.preventDefault();
+ $('a[href="' + $(this).attr('href') + '"]').tab('show');
+ });
+
+ // ------------------------------------------------
+ // End Deep Linking for Bootstrap tabs
+ // ------------------------------------------------
+
+ // Image preview
+ function readURL(input, $preview) {
+ if (input.files && input.files[0]) {
+ var reader = new FileReader();
+ reader.onload = function (e) {
+ $preview.attr('src', e.target.result);
+ };
+ reader.readAsDataURL(input.files[0]);
+ }
+ }
+ function formatBytes(bytes) {
+ if (bytes < 1024) return bytes + " Bytes";else if (bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB";else if (bytes < 1073741824) return (bytes / 1048576).toFixed(2) + " MB";else return (bytes / 1073741824).toFixed(2) + " GB";
+ }
+
+ // File size validation
+ $('.js-uploadFile').bind('change', function () {
+ var $this = $(this);
+ var id = '#' + $this.attr('id');
+ var status = id + '-status';
+ var $status = $(status);
+ var delete_id = $(id + '-deleteCheckbox');
+ var preview_container = $(id + '-previewContainer');
+ $status.removeClass('text-success').removeClass('text-danger');
+ $(status + ' .goodfile').remove();
+ $(status + ' .badfile').remove();
+ $(status + ' .previewSize').hide();
+ preview_container.hide();
+ $(id + '-info').html('');
+ var max_size = $this.data('maxsize');
+ var total_size = 0;
+ for (var i = 0; i < this.files.length; i++) {
+ total_size += this.files[i].size;
+ $(id + '-info').append('
' + htmlEntities(this.files[i].name) + ' (' + formatBytes(this.files[i].size) + ') ');
+ }
+ if (total_size > max_size) {
+ $status.addClass('text-danger').removeClass('help-block').prepend('
').append('
Upload is ' + formatBytes(total_size) + '.');
+ } else {
+ $status.addClass('text-success').removeClass('help-block').prepend('
');
+ var $preview = $(id + '-imagePreview');
+ readURL(this, $preview);
+ $preview.fadeIn();
+ preview_container.fadeIn();
+ delete_id.hide();
+ }
+ });
+});
+function htmlEntities(str) {
+ return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
+}
+
+/**
+ * Toggle disabled
+ */
+(function ($) {
+ $.fn.toggleDisabled = function (callback) {
+ return this.each(function () {
+ var disabled,
+ $this = $(this);
+ if ($this.attr('disabled')) {
+ $this.removeAttr('disabled');
+ disabled = false;
+ } else {
+ $this.attr('disabled', 'disabled');
+ disabled = true;
+ }
+ if (callback && typeof callback === 'function') {
+ callback(this, disabled);
+ }
+ });
+ };
+})(jQuery);
+
+/**
+ * Universal Livewire Select2 integration
+ *
+ * How to use:
+ *
+ * 1. Set the class of your select2 elements to 'livewire-select2').
+ * 2. Name your element to match a property in your Livewire component
+ * 3. Add an attribute called 'data-livewire-component' that points to $this->getId() (via `{{ }}` if you're in a blade,
+ * or just $this->getId() if not).
+ */
+document.addEventListener('livewire:init', function () {
+ $('.livewire-select2').select2();
+ $(document).on('select2:select', '.livewire-select2', function (event) {
+ var target = $(event.target);
+ if (!event.target.name || !target.data('livewire-component')) {
+ console.error("You need to set both name (which should match a Livewire property) and data-livewire-component on your Livewire-ed select2 elements!");
+ console.error("For data-livewire-component, you probably want to use $this->getId() or {{ $this->getId() }}, as appropriate");
+ return false;
+ }
+ Livewire.find(target.data('livewire-component')).set(event.target.name, this.options[this.selectedIndex].value);
+ });
+ Livewire.hook('request', function (_ref) {
+ var succeed = _ref.succeed;
+ succeed(function () {
+ queueMicrotask(function () {
+ $('.livewire-select2').select2();
+ });
+ });
+ });
+});
+
+/***/ }),
+
+/***/ "./resources/assets/js/snipeit_modals.js":
+/*!***********************************************!*\
+ !*** ./resources/assets/js/snipeit_modals.js ***!
+ \***********************************************/
+/***/ (() => {
+
+/*
+ *
+ * Snipe-IT Universal Modal support
+ *
+ * Enables modal dialogs to create sub-resources throughout Snipe-IT
+ *
+ */
+
+/*
+HOW TO USE
+ Create a Button looking like this:
+
New
+ If you don't have access to Blade commands (like {{ and }}, etc), you can hard-code a URL as the 'href'
+ data-toggle="modal" - required for Bootstrap Modals
+data-target="#createModal" - fixed ID for the modal, do not change
+data-select="assigned_to" - What is the *ID* of the select-dropdown that you're going to be adding to, if the modal-create was a success? Be on the lookout for duplicate ID's, it will confuse this library!
+class="btn btn-sm btn-primary" - makes it look button-ey, feel free to change :)
+
+If you want to pass additional variables to the modal (In the Category Create one, for example, you can pass category_id), you can encode them as URL variables in the href
+
+*/
+
+$(function () {
+ var baseUrl = $('meta[name="baseUrl"]').attr('content');
+ //handle modal-add-interstitial calls
+ var model, select, refreshSelector;
+ if ($('#createModal').length == 0) {
+ $('body').append('
');
+ }
+ $('#createModal').on("show.bs.modal", function (event) {
+ var link = $(event.relatedTarget);
+ model = link.data("dependency");
+ select = link.data("select");
+ refreshSelector = link.data("refresh");
+ $('#createModal').load(link.attr('href'), function () {
+ // this sets the focus to be the name field
+ $('#modal-name').focus();
+
+ //do we need to re-select2 this, after load? Probably.
+ $('#createModal').find('select.select2').select2();
+ // Initialize the ajaxy select2 with images.
+ // This is a copy/paste of the code from snipeit.js, would be great to only have this in one place.
+
+ $('.js-data-ajax').each(function (i, item) {
+ var link = $(item);
+ var endpoint = link.data("endpoint");
+ var select = link.data("select");
+ link.select2({
+ ajax: {
+ // the baseUrl includes a trailing slash
+ url: baseUrl + 'api/v1/' + endpoint + '/selectlist',
+ //WARNING - we're hoping that's defined on the page somewhere...
+ dataType: 'json',
+ delay: 250,
+ headers: {
+ "X-Requested-With": 'XMLHttpRequest',
+ "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
+ },
+ data: function data(params) {
+ var data = {
+ search: params.term,
+ page: params.page || 1,
+ assetStatusType: link.data("asset-status-type")
+ };
+ return data;
+ },
+ /*processResults: function (data, params) {
+ params.page = params.page || 1;
+ var answer = {
+ results: data.items,
+ pagination: {
+ more: data.pagination.more
+ }
+ };
+ return answer;
+ },*/
+ cache: true
+ },
+ //escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
+ templateResult: formatDatalistSafe
+ //templateSelection: formatDataSelection
+ });
+ });
+ });
+ });
+ $('#createModal').on('click', '#modal-save', function () {
+ $.ajax({
+ type: 'POST',
+ url: $('.modal-body form').attr('action'),
+ headers: {
+ "X-Requested-With": 'XMLHttpRequest',
+ "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
+ },
+ data: $('.modal-body form').serialize(),
+ success: function success(result) {
+ if (result.status == "error") {
+ var error_message = "";
+ for (var field in result.messages) {
+ error_message += "
Problem(s) with field " + field + ": " + result.messages[field];
+ }
+ $('#modal_error_msg').html(error_message).show();
+ return false;
+ }
+ var id = result.payload.id;
+ var name = result.payload.name || result.payload.first_name + " " + result.payload.last_name;
+ if (!id || !name) {
+ console.error("Could not find resulting name or ID from modal-create. Name: " + name + ", id: " + id);
+ return false;
+ }
+ $('#createModal').modal('hide');
+ $('#createModal').html("");
+ var refreshTable = $('#' + refreshSelector);
+ if (refreshTable.length > 0) {
+ refreshTable.bootstrapTable('refresh');
+ }
+
+ // "select" is the original drop-down menu that someone
+ // clicked 'add' on to add a new 'thing'
+ // this code adds the newly created object to that select
+ var selector = document.getElementById(select);
+ if (!selector) {
+ return false;
+ }
+ selector.options[selector.length] = new Option(name, id);
+ selector.selectedIndex = selector.length - 1;
+ $(selector).trigger("change");
+ if (window.fetchCustomFields) {
+ fetchCustomFields();
+ }
+ },
+ error: function error(result) {
+ msg = result.responseJSON.messages || result.responseJSON.error;
+ $('#modal_error_msg').html("Server Error: " + msg).show();
+ }
+ });
+ });
+});
+function formatDatalistSafe(datalist) {
+ // console.warn("What in the hell is going on with Select2?!?!!?!?");
+ // console.warn($.select2);
+ if (datalist.loading) {
+ return $(' Loading...');
+ }
+ var root_div = $("");
+ var left_pull = $("
");
+ if (datalist.image) {
+ var inner_div = $("
");
+ /******************************************************************
+ *
+ * We are specifically chosing empty alt-text below, because this
+ * image conveys no additional information, relative to the text
+ * that will *always* be there in any select2 list that is in use
+ * in Snipe-IT. If that changes, we would probably want to change
+ * some signatures of some functions, but right now, we don't want
+ * screen readers to say "HP SuperJet 5000, .... picture of HP
+ * SuperJet 5000..." and so on, for every single row in a list of
+ * assets or models or whatever.
+ *
+ *******************************************************************/
+ var img = $("
![]()
");
+ // console.warn("Img is: ");
+ // console.dir(img);
+ // console.warn("Strigularly, that's: ");
+ // console.log(img);
+ img.attr("src", datalist.image);
+ inner_div.append(img);
+ } else {
+ var inner_div = $("
");
+ }
+ left_pull.append(inner_div);
+ root_div.append(left_pull);
+ var name_div = $("
");
+ name_div.text(datalist.text);
+ root_div.append(name_div);
+ var safe_html = root_div.get(0).outerHTML;
+ var old_html = formatDatalist(datalist);
+ if (safe_html != old_html) {
+ // console.log("HTML MISMATCH: ");
+ // console.log("FormatDatalistSafe: ");
+ // console.dir(root_div.get(0));
+ // console.log(safe_html);
+ // console.log("FormatDataList: ");
+ // console.log(old_html);
+ }
+ return root_div;
+}
+function formatDatalist(datalist) {
+ var loading_markup = '
Loading...';
+ if (datalist.loading) {
+ return loading_markup;
+ }
+ var markup = "
";
+ markup += "
";
+ if (datalist.image) {
+ markup += "
";
+ } else {
+ markup += "
";
+ }
+ markup += "
" + datalist.text + "
";
+ markup += "
";
+ return markup;
+}
+function formatDataSelection(datalist) {
+ return datalist.text.replace(/>/g, '>').replace(/ {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "./resources/assets/less/overrides.less":
+/*!**********************************************!*\
+ !*** ./resources/assets/less/overrides.less ***!
+ \**********************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "./resources/assets/less/skins/_all-skins.less":
+/*!*****************************************************!*\
+ !*** ./resources/assets/less/skins/_all-skins.less ***!
+ \*****************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "./resources/assets/less/skins/skin-black-dark.less":
+/*!**********************************************************!*\
+ !*** ./resources/assets/less/skins/skin-black-dark.less ***!
+ \**********************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
/***/ }),
/***/ "./resources/assets/less/skins/skin-black.less":
@@ -92030,71 +92095,6 @@ __webpack_require__.r(__webpack_exports__);
// extracted by mini-css-extract-plugin
-/***/ }),
-
-/***/ "./node_modules/admin-lte/build/less/AdminLTE.less":
-/*!*********************************************************!*\
- !*** ./node_modules/admin-lte/build/less/AdminLTE.less ***!
- \*********************************************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-// extracted by mini-css-extract-plugin
-
-
-/***/ }),
-
-/***/ "./resources/assets/less/app.less":
-/*!****************************************!*\
- !*** ./resources/assets/less/app.less ***!
- \****************************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-// extracted by mini-css-extract-plugin
-
-
-/***/ }),
-
-/***/ "./resources/assets/less/overrides.less":
-/*!**********************************************!*\
- !*** ./resources/assets/less/overrides.less ***!
- \**********************************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-// extracted by mini-css-extract-plugin
-
-
-/***/ }),
-
-/***/ "./resources/assets/less/skins/_all-skins.less":
-/*!*****************************************************!*\
- !*** ./resources/assets/less/skins/_all-skins.less ***!
- \*****************************************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-// extracted by mini-css-extract-plugin
-
-
-/***/ }),
-
-/***/ "./resources/assets/less/skins/skin-black-dark.less":
-/*!**********************************************************!*\
- !*** ./resources/assets/less/skins/skin-black-dark.less ***!
- \**********************************************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-// extracted by mini-css-extract-plugin
-
-
/***/ })
/******/ });
diff --git a/public/mix-manifest.json b/public/mix-manifest.json
index 84f3b91e8..8b34c6437 100644
--- a/public/mix-manifest.json
+++ b/public/mix-manifest.json
@@ -1,9 +1,9 @@
{
- "/js/build/app.js": "/js/build/app.js?id=65d7af7b9fa7fd0e05737526a0d1d282",
+ "/js/build/app.js": "/js/build/app.js?id=607de09b70b83ef82a427e4b36341682",
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=06c13e817cc022028b3f4a33c0ca303a",
"/css/dist/skins/_all-skins.css": "/css/dist/skins/_all-skins.css?id=79aa889a1a6691013be6c342ca7391cd",
- "/css/build/overrides.css": "/css/build/overrides.css?id=6528155ed5ed8fddf4047de7f0d0298d",
- "/css/build/app.css": "/css/build/app.css?id=3422f2ca2056b952c3c361adf00c10b8",
+ "/css/build/overrides.css": "/css/build/overrides.css?id=f188c07f91348503bc38f4b6683993aa",
+ "/css/build/app.css": "/css/build/app.css?id=7f6827b6d2149b8eab327d00e2dd66f0",
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=4ea0068716c1bb2434d87a16d51b98c9",
"/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=7b315b9612b8fde8f9c5b0ddb6bba690",
"/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=ea22079836a432d7f46a5d390c445e13",
@@ -19,7 +19,7 @@
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=a82b065847bf3cd5d713c04ee8dc86c6",
"/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=6ea836d8126de101081c49abbdb89417",
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=76482123f6c70e866d6b971ba91de7bb",
- "/css/dist/all.css": "/css/dist/all.css?id=18ebb9c284b49dcf6c8e4fdb923ad923",
+ "/css/dist/all.css": "/css/dist/all.css?id=fe65a4b6cd3acaf2737dec72b98b650b",
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
"/js/select2/i18n/af.js": "/js/select2/i18n/af.js?id=4f6fcd73488ce79fae1b7a90aceaecde",
@@ -111,5 +111,5 @@
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=ceded08e0cc745a83c13647035b03406",
"/js/build/vendor.js": "/js/build/vendor.js?id=89dffa552c6e3abe3a2aac6c9c7b466b",
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=61285c8ac5ea7b46002ea8c451c94e60",
- "/js/dist/all.js": "/js/dist/all.js?id=21e041dec60e0785db6d64961b13a9b0"
+ "/js/dist/all.js": "/js/dist/all.js?id=cae553daff19b328b3ba51a62f891442"
}
diff --git a/resources/assets/less/overrides.less b/resources/assets/less/overrides.less
index 67ee7030e..bbbb74ec8 100644
--- a/resources/assets/less/overrides.less
+++ b/resources/assets/less/overrides.less
@@ -1163,4 +1163,15 @@ input[type="radio"]:checked::before {
/** this is needed to override ekko-lightboxes card view styles **/
.bootstrap-table .fixed-table-container .table tbody tr .card-view {
display: table-row !important;
-}
\ No newline at end of file
+}
+
+td.text-right.text-padding-number-cell {
+ padding-right: 30px !important;
+ white-space: nowrap;
+}
+
+th.text-right.text-padding-number-footer-cell {
+ padding-right: 20px !important;
+ white-space: nowrap;
+}
+
diff --git a/resources/views/accessories/index.blade.php b/resources/views/accessories/index.blade.php
index a3ea41db2..1c82d782f 100755
--- a/resources/views/accessories/index.blade.php
+++ b/resources/views/accessories/index.blade.php
@@ -34,6 +34,7 @@
data-show-refresh="true"
data-show-footer="true"
data-sort-order="asc"
+ data-footer-style="footerStyle"
id="accessoriesTable"
class="table table-striped snipe-table"
data-url="{{route('api.accessories.index') }}"
diff --git a/resources/views/components/index.blade.php b/resources/views/components/index.blade.php
index 418852095..34f4c9bab 100644
--- a/resources/views/components/index.blade.php
+++ b/resources/views/components/index.blade.php
@@ -25,6 +25,7 @@
data-id-table="componentsTable"
data-search="true"
data-side-pagination="server"
+ data-footer-style="footerStyle"
data-show-columns="true"
data-show-fullscreen="true"
data-show-export="true"
diff --git a/resources/views/consumables/index.blade.php b/resources/views/consumables/index.blade.php
index e2235e86e..08582e557 100644
--- a/resources/views/consumables/index.blade.php
+++ b/resources/views/consumables/index.blade.php
@@ -27,6 +27,7 @@
data-id-table="consumablesTable"
data-search="true"
data-side-pagination="server"
+ data-footer-style="footerStyle"
data-show-columns="true"
data-show-export="true"
data-show-fullscreen="true"
diff --git a/resources/views/licenses/index.blade.php b/resources/views/licenses/index.blade.php
index 82e34b190..94d94d1d4 100755
--- a/resources/views/licenses/index.blade.php
+++ b/resources/views/licenses/index.blade.php
@@ -33,6 +33,7 @@
data-pagination="true"
data-search="true"
data-side-pagination="server"
+ data-footer-style="footerStyle"
data-show-columns="true"
data-show-fullscreen="true"
data-show-export="true"
diff --git a/resources/views/models/index.blade.php b/resources/views/models/index.blade.php
index 6f3f5e78d..5ae3fb945 100755
--- a/resources/views/models/index.blade.php
+++ b/resources/views/models/index.blade.php
@@ -45,6 +45,7 @@
data-search="true"
data-show-footer="true"
data-side-pagination="server"
+ data-footer-style="footerStyle"
data-show-columns="true"
data-toolbar="#modelsBulkEditToolbar"
data-bulk-button-id="#bulkModelsEditButton"
diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php
index 2da7b63b1..b9e02bbbd 100644
--- a/resources/views/partials/bootstrap-table.blade.php
+++ b/resources/views/partials/bootstrap-table.blade.php
@@ -13,6 +13,7 @@