Lottermetall24.de receives about 3957 visitors in one month. That could possibly earn $19.79 each month or $0.66 each day. Server of the website is located in Germany. It took our server 2.24 seconds to reach and load the main page of Lottermetall24.de. This does not include JavaScript, image and CSS files load timing. This is a good result. This result is good enough, but there is a room for improvement. If you would like to investigate please refer to the link at the bottom of this page.
Is lottermetall24.de legit? | |
Website Value | $357 |
Alexa Rank | 1185707 |
Monthly Visits | 3957 |
Daily Visits | 132 |
Monthly Earnings | $19.79 |
Daily Earnings | $0.66 |
Country: Germany
Metropolitan Area: Eschborn
Postal Reference Code: 65760
Latitude: 50.1433
Longitude: 8.5711
HTML Tag | Content | Informative? |
---|---|---|
Title: | Anmelden - | Could be improved |
Description: | Not set | Empty |
H2: | Shop-Login | Is it informative enough? |
Results will appear here |
|
Pingdom - Web transfer-speed test from Pingdom
Run diagnostic transfer-rate tests on each page or individual page components (JS, .img, and HTML code) with Pingdom for lottermetall24.de
Google’s Web Analytics Google provides many analytical tools for the web that will help you find out the number of visitors, their locations and activities when logging onto lottermetall24.de
Alexa - lottermetall24.de on Alexa Traffic Rank Data
Alexa provides a charting service that shows global position by audience, engagement, and time spent on lottermetall24.de
Majestic Backlinks - Lookup other webpages that have hyperlinks leading to lottermetall24.de.
Google Index - Which of the pages is Google.com indexing?
Find out which pages from lottermetall24.de have made it into Google.com’s listings. You can find out with the "site:" query.
Website on this IP by Bing - All sites on the same 212.211.170.136 IP
View a list of websites with an IP matching that of lottermetall24.de from Bing.com
/datenschutzerklaerung: | |
---|---|
Title |
datenschutzerklaerung - Lottermetall |
Description |
datenschutzerklaerung |
H1 |
Datenschutzerklärung |
H2 |
{{shortText}} {{itemNumberLabel}}: {{itemNumber}} {{#recommendedPrice}} {{recommendedPrice}} {{/recommendedPrice}} {{effectivePrice}} {{#effectivePriceSuffix}} {{effectivePriceSuffix}} {{/effectivePriceSuffix}} {{#secondaryPrice}} {{secondaryPrice}} {{secondaryPriceSuffix}} {{/secondaryPrice}} {{priceQuantityLabel}} {{priceQuantity}} '; function loadItemText() { var overwriteLongtext = true; var $longtext = $(#output-longtext); if (overwriteLongtext || $longtext.length === 0 || isEmpty($longtext.html().trim())) { loadOxomiItemText(); } } /** * Increments the item quantity by a certain amount * * Uses toFixed to round the result to the right number of decimals to prevent errors due to floating point * arithmetic. * * @param id the ID of the input field to increment * @param orderStep the amount to increment */ function incrementItemQuantity(id, orderStep) { var $input = $('#' + id); var result = parseFloat((parseFloat($input.val()) + orderStep).toFixed(3)); $input.val(result); } /** * Decrements the item quantity by a certain amount * * Uses toFixed to round the result to the right number of decimals to prevent errors due to floating point * arithmetic. * * @param id the ID of the input field to decrement * @param orderStep the amount to decrement * @param minOrderQuantity the minimum order quantity */ function decrementItemQuantity(id, orderStep, minOrderQuantity) { var $input = $('#' + id); var result = parseFloat((parseFloat($input.val()) - orderStep).toFixed(3)); if (result < minOrderQuantity) { $input.val(minOrderQuantity); } else { $input.val(result); } } var IMAGE_OVERLAY_TEMPLATE = '' + ' ' + ' ' + ' {{#images}}' + ' ' + ' ' + ' ' + ' ' + ' ' + ' {{/images}}' + ' ' + ' ' + ' ' + ' ' + ' ' + ''; function createImageOverlay($container) { // Event handler that opens the item image overlay and displays the clicked image var showArrows = true; var fadeIn = false; $container.on('click', 'a', function (e) { e.preventDefault(); var currentUrl = $(this).attr('href'); var currentIndex = 0; var images = []; // Find all item images and the index of the one that was clicked TODO $container.find('.item-image-js').filter(function (index, element) { return !$(element).parent().hasCl ('slick-cloned'); }).each(function (index, element) { var url = $(element).attr('href'); images.push(url); if (url === currentUrl) { currentIndex = index; } }); // Generate and add the overlay to the DOM var $overlay = $(Mustache.render(IMAGE_OVERLAY_TEMPLATE, {'images': images})); var $slider = $overlay.find('.image-overlay-images-js'); $('body').addCl ('image-overlay-open').append($overlay); if (fadeIn) { $overlay.hide().fadeIn(); } // Generate the slider $slider.slick({ slidesToShow: 1, dots: true, arrows: showArrows, initialSlide: currentIndex }); // Event handler for pressing escape, left/right arrow keys var keydownHandler = function (e) { if (e.keyCode === 27) { closeOverlay(); } else if(e.keyCode === 37) { $slider.slick('slickPrev'); } else if(e.keyCode === 39) { $slider.slick('slickNext'); } }; // Function that closes the overlay and removes the escape key event handler var closeOverlay = function (e) { $('body').removeCl ('image-overlay-open'); $overlay.remove(); $(do ent).off('keydown', keydownHandler); }; // Click on the close on closes the overlay $overlay.find('.image-overlay-close').click(function (e) { e.preventDefault(); closeOverlay(); }); // Click on the background closes the overlay $overlay.click(function (e) { if (e.target !== this) { return; } closeOverlay(); }); // Event handler for keyboard inputs $(do ent).keydown(keydownHandler); }); } var AUTOCOMPLETE_SUGGESTION_TEMPLATE = '' + ' {{label}}' + ' {{#isERPAddress}}' + ' ' + ' Nicht veränderbar' + ' ' + ' {{/isERPAddress}}' + ' {{#hasDescription}}' + ' ' + ' {{#descriptionLines}}' + ' {{.}}' + ' {{/descriptionLines}}' + ' ' + ' {{/hasDescription}}' + ''; function enableAutocomplete(field) { function createSubmitData(key, value) { var data = {}; var fieldData = field.data(); for(f in fieldData) { if (fieldData.hasOwnProperty(f)) { if (f != 'autocomplete' && f != 'optional' && f != 'select2') { data[f] = fieldData[f]; } } } data[key] = value; return data; } if (field.data('optional') && field.is(:empty)) { field.prepend(''); } field.on('select2:open', function (e) { $('.select2-search__field').each(function(e) { var search = $(this); if (search.parent().hasCl ('select2-search--inline')) { // Don't add placeholder and graphic to inline search fields return; } search.css({ 'background-image': 'url(/ ets/wondergem/select2/chosen-sprite.png)', 'background-repeat': 'no-repeat', 'background-position': '100% -22px' }); var placeholder = field.attr('data-searchtext'); if (typeof placeholder === 'undefined' || placeholder === '') { placeholder = 'Geben Sie einen Suchtext ein…'; } search.attr('placeholder', placeholder); }); }); field.on('select2:unselect', function(e) { $(this).html(''); e.preventDefault(); e.stopPropagation(); }); field.select2({ allowClear: field.data('optional'), placeholder: 'Ihre Auswahl…', dropdownParent: field.parent(), minimumInputLength: 0, tags: field.data('dynamic-option'), templateResult: function (result) { if (typeof result === 'undefined') { return undefined; } var hasDescription = typeof result.description !== 'undefined' && result.description !== ''; if (field.attr('data-multiline')) { return $(Mustache.render(AUTOCOMPLETE_SUGGESTION_TEMPLATE, { 'label': result.text, 'hasDescription' : hasDescription, 'descriptionLines': hasDescription ? result.description.split(' ') : undefined, 'isERPAddress': isERPAddress(result.id) })); } return hasDescription ? result.description : result.text; }, language : { loadingMore: function() { return 'Lade Daten…'; }, searching: function () { return 'Suche…'; }, noResults: function () { return 'Keine Suchtreffer…'; } }, ajax: { url: '/' + field.data('autocomplete'), dataType: 'jsonp', quietMillis: 100, data: function(term, page) { return createSubmitData('query', term.term); }, processResults: function (data, page) { return { results: data.completions, more: false }; } } }); } function isERPAddress(addressAsJson) { try { return JSON.parse(addressAsJson).isERPAddress; } catch(e) { return undefined; } } $(do ent).ready(function() { $('select[data-autocomplete]').each(function(e) { var field = $(this); enableAutocomplete(field); }); $('.select2-select').each(function(e) { var field = $(this); if (field.data('optional')) { field.prepend(''); } field.select2({ allowClear: field.data('optional'), placeholder: 'Ihre Auswahl…', dropdownParent: field.parent(), minimumResultsForSearch: 10, width : '100%', language : { maximumSelected: function(args) { return 'Sie können maximal ' + args.maximum + ' Elemente auswählen'; }, searching: function () { return 'Suche…'; }, noResults: function () { return 'Keine Suchtreffer…'; } }, escapeMarkup: function(m) { // Do not escape HTML in the select options text return m; } }); }); }); function initializeMEMOIO() { $('').prependTo($('head')); $(do ent).one('memoio-ready', function () { memoio.initSettings({ email: '', name: '', showBadge: 'never' }); $('.memoio-flap').removeCl ('hidden'); }); $('').appendTo($('head')); } /** * Cleans up all MEMOIO settings variables which are set by the integration. * The settings are cleaned up to avoid wrong values being set when calling * different conversations on the same page. */ function cleanupMEMOIOSettings() { memoio.initSettings({ partner: '', silentMessage: '', topic: '', reference: '', skipTopic: false }); } /** * Starts a conversation with the shop's support channel. */ function talkToUs() { return talkToChannel('JA6AT5NFJ1IK0V9DGD9GP6BS74'); } /** * Starts a conversation with the given channel. * * @param channelId the unique id of the channel to talk to */ function talkToChannel(channelId) { chatWithChannel(channelId, '', '', 'Die Anfrage wurde auf der Seite https://lottermetall24.de/datenschutzerklaerung Ihres Shop-Systems gestartet.'); return false; } /** * Starts a conversation with the given mail. * * @param email the email of the person to talk to */ function talkToMail(email) { cleanupMEMOIOSettings(); memoio.initSettings({ partner: 'email:' + email, silentMessage: 'Die Anfrage wurde auf der Seite https://lottermetall24.de/datenschutzerklaerung Ihres Shop-Systems gestartet.' }); memoio.show(); return false; } /** * Starts a conversation with the given person. * * @param personId the unique id of the person to talk to */ function talkToPerson(personId) { chatWithChannel(personId, '', '', 'Die Anfrage wurde auf der Seite https://lottermetall24.de/datenschutzerklaerung Ihres Shop-Systems gestartet.'); return false; } /** * Starts a memoio chat with the person represented by the memoio talkToMeId. * * @param talkToMeId the unique id of the person to talk to * @param topic optional, the topic of the conversation * @param reference optional, multiple references can be set comma separated * @param initialMessage optional, the initial message that is sent, after the chat is started * @param skipTopic optional, if the topic should not be requested from the user */ function chatWithPerson(talkToMeId, topic, reference, initialMessage, skipTopic) { cleanupMEMOIOSettings(); memoio.initSettings({ partner: 'person:' + talkToMeId, topic: topic, reference: reference, silentMessage: initialMessage, skipTopic: skipTopic }); memoio.show(); } /** * Starts a memoio chat with a channel represented by the memoio channelId. * * @param channelId the unique id of the channel to talk to * @param topic optional, the topic of the conversation * @param reference optional, multiple references can be set comma separated * @param initialMessage optional, the initial message that is sent, after the chat is started * @param skipTopic optional, if the topic should not be requested from the user */ function chatWithChannel(channelId, topic, reference, initialMessage, skipTopic) { cleanupMEMOIOSettings(); memoio.initSettings({ partner: 'channel:' + channelId, topic: topic, reference: reference, silentMessage: initialMessage, skipTopic: skipTopic }); memoio.show(); } $(do ent).ready(function () { initializeMEMOIO(); }); /** * Fetches the memoio person information. * * @param talkToMeId to unqiue person id which identifies a memoio contact * @param uniqueId the unique element id */ function getMemoioPersonInformation(talkToMeId, uniqueId) { var uri = https://memoio.com/api/person-info; return jsonRequest(uri, { talkToMeId: talkToMeId }).then(function (json) { var $memoioElement = $(# + uniqueId); var $avatar = $memoioElement.find(.img-js); if (isEmpty(json.avatar)) { $avatar.remove(); } else { $avatar.prop(src, json.avatar); } var $name = $memoioElement.find(.name-js); $name.html(json.name); if (json.status === ACTIVE) { $name.after(''); } $afterName = $name.parent(); if (!isEmpty(json.position)) { $afterName.after(Mustache.render('{{position}}', json)); } if (!isEmpty(json.awayInfo)) { $afterName.after(Mustache.render('{{awayInfo}}', json)); } }).catch(function(){ $(# + uniqueId).remove(); }); } function getChannelInformation(channelId, uniqueId){ var uri = https://memoio.com/api/channel-info; return jsonRequest(uri, { channel: channelId }).then(function (json) { var $memoioElement = $(# + uniqueId); var $avatar = $memoioElement.find(.img-js); if (isEmpty(json.avatar)) { $avatar.remove(); } else { $avatar.prop(src, json.avatar); } var $name = $memoioElement.find(.name-js); $name.html(json.name); if (json.open) { $name.after(''); } $afterName = $name.parent(); if (!isEmpty(json.description)) { $afterName.after(Mustache.render('{{description}}', json)); } if (!isEmpty(json.message)) { $afterName.after(Mustache.render('{{message}}', json)); } }).catch(function(){ $(# + uniqueId).remove(); }); } /** * Retrives Information about known items from shop for Infoplay. */ function infoplayItemLookup(infoplayData, next) { fillSelection(infoplayData); if (infoplayData.isSelectedAlternative) { $.getJSON( '/items/api/infos', { uniqueItemNumber: infoplayData.uniqueItemNumber }, function (json) { if (json.error) { oxomi.showMessageInDialog(Fehler, json.message); } else { infoplayData.items.push(renderInfoplayItem(json.item, infoplayData)); next(infoplayData); } } ); } else { $.getJSON( '/items/api/infoplay', { query: infoplayData.itemNumber, supplierNumber: infoplayData.supplierNumber }, function (json) { if (json.error) { oxomi.showMessageInDialog(Fehler, json.message); } else { for (i = 0; i < json.items.length; i++) { infoplayData.items.push(renderInfoplayItem(json.items[i], infoplayData)); } next(infoplayData); } } ); } } /** * Generates an item object for Infoplay. */ function renderInfoplayItem(item, infoplayData) { var newItem = { itemNumber: item.itemNumber, uniqueItemNumber: item.uniqueItemNumber, itemUrl: '/item/' + item.uniqueItemNumber, supplierName: item.brandName, shortText: item.shortText, previewImageUrl: item.previewImageUrl, quantity: item.minOrderQuantityUser, reresolve: true, features: [] }; var priceString = item.effectivePrice; if (item.hasEffectivePrice) { priceString = priceString + + item.effectivePriceSuffix; } var availability = item.stockText; if (item.additionalStockText) { availability = availability + + item.additionalStockText; } newItem.features.push({ fields: [ {name: item.effectivePriceName, value: priceString}, {name: 'Preismenge', value: item.priceQuantity}, {name: 'Min. Bestellmenge', value: item.minOrderQuantity}, {name: 'Bestellschritt', value: item.orderStep}, {name: 'Verfügbarkeit', value: availability, span: true} ] }); return newItem; } /** * Basket handler for known items in shop via Infoplay. */ function infoplayBasket(infoplayData, next) { var machineQuantity = infoplayData.quantity.replace(/./g, '').replace(',', '.'); addItemToBasket(infoplayData.item.uniqueItemNumber, machineQuantity) .then(function (response) { return infoplaySuccessMessage(response, infoplayData, next); }) .then(refreshBasketInfo) .catch(function (response) { return infoplayErrorMessage(response, infoplayData, next); }); } /** * Safely fills in custom attribute selection in infoplayData * which is needed for div items. */ function fillSelection(infoplayData) { if (!infoplayData.selection) { infoplayData.selection = infoplayData.itemNumber; } } /** * Function to show success message for Infoplay add to basket */ function infoplaySuccessMessage(response, infoplayData, next) { infoplayData.basketMessage = 'Ihr Warenkorb wurde aktualisiert: ' + response.basketInfo; next(infoplayData); return response; } /** * Function to show error message for Infoplay add to basket */ function infoplayErrorMessage(response, infoplayData, next) { infoplayData.basketMessage = response.message; next(infoplayData); return response; } /** * Injects link into Infoplay dialog to request div item. */ function enhanceExternalInfoplay(infoplayData, infoplayExternalLookup, processInfoplayItemResult) { var addDivItemCallback = function (infoplayDataFilled) { fillSelection(infoplayDataFilled); for (i = 0; i < infoplayDataFilled.items.length; i++) { infoplayDataFilled.items[i].features = [linkForDivItem(infoplayDataFilled)]; } processInfoplayItemResult(infoplayDataFilled); }; infoplayExternalLookup(infoplayData, addDivItemCallback); } /** * Handler for adding div items to basket via Infoplay. */ function infoplayExternalBasket(infoplayData, next) { var supplierItem = { supplier: infoplayData.item.supplierName, supplierNumber: infoplayData.supplierNumbers.join(), supplierItemNumber: infoplayData.item.itemNumber, shorttext: infoplayData.item.shortText, quantity: infoplayData.quantity, externalUrl: generateOxomiCatalogUrl(infoplayData), comment: generateCatalogComment(infoplayData), priceQuantity: infoplayData.item.priceQuantity, unitCode: infoplayData.item.quantityUnit } addUserDefinedItemToBasket(supplierItem) .then(function (response) { return infoplaySuccessMessage(response, infoplayData, next); }) .then(refreshBasketInfo) .catch(function (response) { return infoplayErrorMessage(response, infoplayData, next); }); } /** * Template for custom Infoplay dialog to add div item. */ var OXOMI_INFOPLAY_TEMPLATE = '' + ' ' + ' ' + ' Artikelnummer' + ' ' + ' ' + ' ' + ' Hersteller' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ''; /** * Renders custom dialog for div items. */ function renderCustomDialog(infoplayData) { var dialog = $(OXOMI_INFOPLAY_TEMPLATE); var submitFunction = function () { infoplayData.quantity = $(#oxomi-quantity).val(); infoplayData.item = { itemNumber: $(#oxomi-itemNumber).val(), supplierName: $(#oxomi-supplier).val() }; infoplayExternalBasket(infoplayData, function (infoplayData) { oxomi.showMessageInDialog($('#oxomi-dialog-title').text(), infoplayData.basketMessage); }); }; $('#oxomi-add-to-basket', dialog).click(submitFunction); $('#oxomi-quantity', dialog).keypress(function (e) { if (e.which == 13) { submitFunction(); } }); $(#oxomi-supplier, dialog).val(infoplayData.brandName); $(#oxomi-itemNumber, dialog).val(infoplayData.selection); oxomi.fillDialog('Diversartikel erf en', dialog); } /** * Adds link to request a div item with logic to add the item to basket. */ function linkForDivItem(infoplayData) { return { title: 'Diversartikel', fields: [{ value: $('Nicht der p ende Artikel? Hier Diversartikel anfragen').click(function () { renderCustomDialog(infoplayData); }), span: true }] }; } /** * Template for catalog URL in div item infos. */ var OXOMI_CATALOG_URL_TEMPLATE = 'https://oxomi.com/p/1554493/catalog/{{catalogId}}?page={{pageNum}}&query={{query}}'; /** * Generates URL from which catalog the item was requested. */ function generateOxomiCatalogUrl(infoplayData) { return Mustache.render(OXOMI_CATALOG_URL_TEMPLATE, { catalogId: infoplayData.catalogId, pageNum: infoplayData.pageNum, query: encodeURIComponent(infoplayData.selection) }); } /** * Generates comment for catalog information. */ function generateCatalogComment(infoplayData) { var commentString = ; if (typeof infoplayData.catalogName != 'undefined') { commentString = Mustache.render('Aus {{catalogName}} (Seite {{visiblePageNum}}) von {{brandName}}', { catalogName: infoplayData.catalogName, visiblePageNum: infoplayData.visiblePageNum, brandName: infoplayData.brandName }); } return commentString; } /** * Renders div item if no item was found in shop and OXOMI. */ function infoplayEmptyResult(infoplayData, next) { fillSelection(infoplayData); renderCustomDialog(infoplayData); oxomi.showDialog(); } setTimeout(function () { var script = do ent.createElement(script); script.type = text/ ascript; script.src = https://oxomi.com/ ets/frontend/oxomi.js do ent.getElementsByTagName(head)[0].appendChild(script); }, 0); function oxomi_ready() { var settings = { server: 'https://oxomi.com', portal: '1554493', infoplayItemLookup: infoplayItemLookup, infoplayMenuTitle: 'Zum Warenkorb hinzufügen...' }; oxomi.init(settings); } // don't do a code format in here: this would mess up everything $(do ent).ready(function () { }); var BASKET_DISCOUNT_HEADER_TEMPLATE = '' + ' ' + ' ' + ' {{discountProgressText}}' + ' ' + ' ' + ' {{#barStatus}}' + ' ' + ' {{/barStatus}}' + ' ' + ' '; var ITEM_PRICE_SCALE_TABLE_ENTRY_TEMPLATE = '' + ' {{scaleDescription}}' + ' ' + ' ' + ' Menge übernehmen' + ' ' + ' ' + ' ' + ' {{scalePrice}}' + ' je {{priceQuantity}}' + ' ' + ''; function clearMessages() { $(#messageBox).hide() $(#messageBox).empty(); } function hasMessage() { return !($(#messageBox).css('display') == 'none'); } function addMessage(type, message, action, actionLabel, details) { var completeMessage = message; if (!isEmpty(actionLabel) && $.isFunction(action)) { completeMessage += '' + actionLabel + ''; } else if (!isEmpty(actionLabel)) { completeMessage += ' ' + actionLabel + ''; } if (details == persistent) { addPersistentMessage(type, message, action, actionLabel); } else { notify(type, completeMessage); } } function notify(type, message) { var $notify = $.notify({ // options message: message, icon: 'fa fa-check-circle-o' }, { // settings type: type, offset: { x: 0, y: 0 }, placement: { from: 'top', align: 'center' }, newest_on_top: true, animate: { enter: 'animated slideInDown', exit: 'animated slideOutUp' }, template: '' + '' + ' ' + '{1}' + '{2}' + '' }); $messages.push($notify); } /** * Pushes the Footer to the bottom of the viewport */ function calcContentHeight() { var newHeight = $(window).height() - $('.footer').outerHeight(true); $('.wrapper-js').css('min-height', newHeight + 'px'); } $(do ent).ready(function (e) { $(window).resize(calcContentHeight); calcContentHeight(); }); /** * Calculates content container height to make sure sidebar-filter is long enough */ function calcSidebarHeight() { var newSidebarHeight = $(window).height() - $('.footer').outerHeight(true) - $('.header').outerHeight(true); $('.sidebar-filter-js').css('min-height', newSidebarHeight + 'px'); } $(window).load(function () { $(window).resize(calcSidebarHeight); calcSidebarHeight(); }); /** * Shows success message for basket refresh */ function showBasketSuccessMessage(response) { addMessage(page-alert alert-success, response.message, /basket, 'Warenkorb anzeigen'); return response; } function fileUpload(url, target, params, allowedExtensions) { var container = target; new qq.FileUploader({ element: target, action: url, params: params, debug: false, onComplete: function (cmp_id, fileName, responseJSON) { clearMessages(); // the basket file uploader overwrites the normal file uploader logic if (responseJSON.basketUploadHandling) { handleBasketFileUploaderResponse(responseJSON); return; } // the customer item numbers uploader needs to be handled differently if (!isEmpty(responseJSON.redirectUri)) { loadUrl(responseJSON.redirectUri); return; } // default handling handleDefaultFileUploaderResponse(responseJSON); }, showMessage: function (message) { // We generally send a flag error which is true or false as // part of the response. Sadly, fileUploader.js checks for this // flag (expecting a string) and invokes showMessage is present. // Therefore we have to filter this here :-/ if (message !== true) { clearMessages(); addError(message); } }, messages: { typeError: 'Ungültiger Dateityp', sizeError: 'Datei zu groß', minSizeError: 'Datei zu klein', emptyError: 'Datei ist leer' }, allowedExtensions: allowedExtensions, template: '' + 'Ziehen Sie Dateien hierher, um diese hochzuladen…' + 'Datei auswählen…' + '' + '', fileTemplate: '' + '' + '' + '' + 'Abbrechen' + 'Upload fehlgeschlagen' + '' }); } function addInfo(message, action, actionLabel) { if (action) { $('' + message + ' ' + actionLabel + '').appendTo($('#messageBox')); } else { $('').html(message).appendTo($('#messageBox')); } } function addError(message) { $('').html(message).appendTo($('#messageBox')); } /** * Refreshes the basket info in the header section */ function refreshBasketInfo(response) { $('.header-basket-sum-js').html( + response.basketPrice + ); $('.header-basket-badge-js').text(response.basketPositions); if (response.showBasketDiscountBar) { $('.basket-discount-header-wrapper').removeCl ('hide'); $('.basket-discount-header-wrapper').html(Mustache.render(BASKET_DISCOUNT_HEADER_TEMPLATE, { discountProgressText: response.discountProgressText, barStatus: response.barStatus })); } else { $('.basket-discount-header-wrapper').addCl ('hide'); } return response; } /** * A file uploaded to the basketUploader requires a special response handling. */ function handleBasketFileUploaderResponse(responseJSON) { if (responseJSON.error) { addError(responseJSON.message); } else if (responseJSON.success) { showBasketSuccessMessage(responseJSON); refreshBasketInfoAsync(responseJSON); if (responseJSON.warning) { addWarningMessage(responseJSON.warningMessage); } } $(#messageBox).show(); } /** * The json response handling for customer item number uploads in the frontend. */ function handleCustomerItemNumbersUploaderResponse(responseJSON) { loadUrl(/settings/customer-item-numbers); } /** * The default json response handling for file uploads in the frontend. */ function handleDefaultFileUploaderResponse(responseJSON) { if (responseJSON.error) { addError(responseJSON.message); } else if (responseJSON.success) { if (responseJSON.message) { addSuccessMessage(responseJSON.message); } if (responseJSON.warning) { addWarningMessage(responseJSON.warningMessage); } if (responseJSON.errorDetails) { addInfo(responseJSON.errorDetails); } } $(#messageBox).show(); } /** * Adds all items to the basket with the given quantity. * * Searches for d:textfields within the given jquery $element. * Expects the id to be the uniqueItemNumber and the wanted quantity the value of the textfield. * * Will ignore textfields with an empty value. * * @param $element the jquery element containing the textfields */ function addAllToBasket($element) { waitForLoadedToAddItems($element); } function waitForLoadedToAddItems($element) { var waited = false; $element.find(input[type=number]).each(function () { if (isEmpty($(this).val())) { return; } var $parent = $(this).parent().parent(); if ($parent.data(loaded)) { return; } waited = true; showLoadingSpinner(); if (!$parent.data(load-running)) { loadTooltip($parent.data(identifier), $parent.data(item-number), undefined, true); } }); if (!waited) { addMultipleMatrixItems(fetchMatrixPositions($element)); return; } setTimeout(function () { waitForLoadedToAddItems($element); }, 200) } function fetchMatrixPositions($element){ var matrixPositions = []; $element.find(input[type=number]).each(function () { var item = { quantity: $(this).val(), uniqueItemNumber: $(this).attr(name), itemNumber: $(this).parent().parent().data(item-number) }; if (!isEmpty(item.quantity)) { matrixPositions.push(item); } $(this).val(); }); return matrixPositions; } function addMultipleMatrixItems(matrixPositions) { if (matrixPositions.length === 0) { return; } postJSONContent(/api/basket/add-multiple-matrix-items, { positions: matrixPositions }, false, true) .then(function (response) { if (response.missed) { addErrorMessage(response.message); } else { showBasketSuccessMessage(response); } return response; }) .then(refreshBasketInfoAsync) .catch(showBasketErrorMessage); } /** * Loads the tooltip information by requesting the needed information from the server. * * Tooltip information of an item containing the short text, price and some other information. * Will only load the information once for each element. * * @param elementId the unique id used to identify the tooltip element * @param itemNumber of the item the information is requested for. * @param event the event triggering this function * @param hideTooltip if true the request is fired, but the popover element is not shown */ function loadTooltip(elementId, itemNumber, event, hideTooltip) { var stockInfo = + {{stockText}} var description = {{shortText}}; var priceInformation = 'Mein Preis {{effectivePriceSuffix}}: {{effectivePrice}} (je {{priceQuantity}})'; priceInformation += 'Mindestbestellmenge: {{minOrderQuantity}}'; priceInformation += 'Bestellschritt: {{orderStep}}'; var additionalFeatureInfos = '{{#additionalFeatureInfos}}{{featureName}}: {{featureText}}{{/additionalFeatureInfos}}'; // the actual logic starts here var element = $('#tooltip-' + elementId); if (element.data(loaded) === true) { return; } var itemInput = $(#item- + elementId); element.data(load-running, true); jsonRequest(/items/api/tooltip, {itemNumber: itemNumber}).then(function (json) { if (event !== undefined && $(event.target).is(a)) { loadUrl(/item/ + json.uniqueItemNumber); return; } element.data(loaded, true); element.data(load-running, false); if (!hideTooltip) { element.data(bs.popover).options.content = Mustache.render(description + stockInfo + priceInformation + additionalFeatureInfos, json); element.data(bs.popover).setContent(); element.popover(hide); element.popover(show); } $(#item-link- + elementId).attr(href, /item/ + json.uniqueItemNumber); itemInput.attr(name, json.uniqueItemNumber); }).catch(function (json) { element.data(loaded, true); element.data(load-running, false); element.data(bs.popover).options.content = json.message; element.data(bs.popover).setContent(); element.popover(hide); element.popover(show); itemInput.attr(readonly, readonly); itemInput.val(); $(#item-link- + elementId).html(itemNumber + ' (Nicht vorhanden)'); }); } /** * Initializes all tooltip elements on the given page. */ function initializeTooltips() { $(.small-magic-item-box-js).each(function () { var uniqueId = $(this).data(identifier); var itemNumber = $(this).data(item-number); $(this).click(function (e) { loadTooltip(uniqueId, itemNumber, e); }); $(this).popover({ html: true, trigger: focus, placement: auto top, title: function () { return 'Artikel: ' + itemNumber; }, content: function () { return 'Anfrage läuft...'; } }); }); } $(do ent).ready(function () { initializeTooltips(); }); function submitSearchForRangeFilter() { $(#searchFieldForm).submit(); } /** * Shows a loading spinner */ function showLoadingSpinner() { $(body).css(cursor, wait); } /** * Hides a previously shown loading spinner */ function hideLoadingSpinner() { $(body).css(cursor, default); } /** * polyfill for the date.now method * see: https://developer.mozilla.org/de/docs/Web/ aScript/Reference/Global_Objects/Date/now */ if (!Date.now) { Date.now = function now() { return new Date().getTime(); }; } /** * polyfill for the array.includes method * see https://developer.mozilla.org/de/docs/Web/ aScript/Reference/Global_Objects/Array/includes */ if (!Array.prototype.includes) { Array.prototype.includes = function (searchElement /*, fromIndex*/) { 'use strict'; if (this == null) { throw new TypeError('Array.prototype.includes called on null or undefined'); } var O = Object(this); var len = parseInt(O.length, 10) || 0; if (len === 0) { return false; } var n = parseInt(arguments[1], 10) || 0; var k; if (n >= 0) { k = n; } else { k = len + n; if (k < 0) { k = 0; } } var currentElement; while (k < len) { currentElement = O[k]; if (searchElement === currentElement || (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN return true; } k++; } return false; }; } /** * Polyfill for the String.startsWith function * see https://developer.mozilla.org/de/docs/Web/ aScript/Reference/Global_Objects/String/startsWith#Polyfill */ if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position) { position = position || 0; return this.indexOf(searchString, position) === position; }; } /** * Polyfill for the String.endsWith function * see https://developer.mozilla.org/de/docs/Web/ aScript/Reference/Global_Objects/String/endsWith */ if (!String.prototype.endsWith) { String.prototype.endsWith = function(searchString, position) { var subjectString = this.toString(); if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { position = subjectString.length; } position -= searchString.length; var lastIndex = subjectString.indexOf(searchString, position); return lastIndex !== -1 && lastIndex === position; }; } window.sirius = window.sirius || {}; function asFunction(possibleFunction) { return typeof possibleFunction === function ? possibleFunction : Function(); } /** * Bundles some functions and constants for jquery press key events. */ sirius.keys = (function () { // fix physical keyboard bug on iPad that returns keyCode 0 on keyup var ipadFixMap = { Backspace: 8, Tab: 9, Enter: 13, Control: 17, Escape: 27, : 32, ArrowUp: 38, ArrowDown: 40, ,: 188 }; /** * Holds information about all pressed keys. * * If a key is pressed pressedKeys[keyCode] is set to true, else false. * If the key was never pressed at all pressedKeys[keyCode] is undefined */ var pressedKeys = {}; var events = { keyDown: [], keyUp: [] }; return { KEY_BACKSPACE: 8, KEY_TAB: 9, KEY_ENTER: 13, KEY_SHIFT: 16, KEY_ESC: 27, KEY_ARROW_UP: 38, KEY_ARROW_DOWN: 40, KEY_SEMICOLON: 186, KEY_COMMA: 188, eventNames: function () { return Object.keys(events); }, /** * Adds event handlers. * * @param name of the event * @param callback the function to be executed if the event is triggered */ on: function (name, callback) { if (this.eventNames().includes(name)) { events[name].push(asFunction(callback)); } else { throw Callback + name + is no valid event.; } }, /** * Unbinds one or all event handlers. * * @param name of the event * @param callback the function to unbind, if left empty all handlers are removed */ off: function (name, callback) { if (!this.eventNames().includes(name)) { throw Callback + name + is no valid event.; } if (callback === undefined) { events[name] = []; return; } var remainingHandlers = events[name].filter(function (value) { return value !== asFunction(callback); }); events[name] = remainingHandlers; }, enableKeyUpIpadSupport: function (event) { if (event.keyCode === 0 && event.key) { event.keyCode = event.which = ipadFixMap[event.key]; } }, enableInternetExplorer: function (e) { return e || event; }, /** * Helper method which will call all browser & event specific helper functions. */ browserFixes: function (e) { e = this.enableInternetExplorer(e); this.enableKeyUpIpadSupport(e); return e; }, /** * Register event listeners to detect multiple pressed keys * * every pressed key is saved within the map object * to detected if a key is pressed simple check for map[$keyCode] * * @param $element which should listen to the key down / key up events * @return object of pressed key */ registerMultipleKeyListener: function ($element) { $element.on(keydown.sirius-keys, function (e) { e = sirius.keys.browserFixes(e); pressedKeys[e.keyCode] = true; events.keyDown.forEach(function (handler) { handler(e); }); }); $element.on(keyup.sirius-keys, function (e) { e = sirius.keys.browserFixes(e); pressedKeys[e.keyCode] = false; events.keyUp.forEach(function (handler) { handler(e); }); }); }, /** * Checks if one or multiple keyCodes are pressed. * * This method can be used to check for custom defined short cuts (e.g. shift and enter). * * @param keyCodes can be a string representation of the keyCode or an array of strings * @return {boolean} true if all requested keyCodes are pressed, false otherwise */ isPressed: function (keyCodes) { if (typeof keyCodes !== object) { return pressedKeys[keyCodes] || false; } var allKeysPressed = true; $.each(keyCodes, function (index, keyCode) { if (pressedKeys[keyCode] !== true) { allKeysPressed = false; return false; } }); return allKeysPressed; } } }()); window.sirius = window.sirius || {}; function asFunction(possibleFunction) { return typeof possibleFunction === function ? possibleFunction : Function(); } sirius.createAutocomplete = (function () { /** * Small object which defines some properties (width & position) of the completion div. * * The anchor can be the same as the input field but it is not necessary. * @type {{name: string, element: undefined, init: init}} */ var anchor = { name: autocomplete-anchor, element: undefined, init: function (name) { if (name !== undefined) { this.name = name; } this.element = $(# + this.name); if (!this.element.length) { throw Anchor does not exist } } }; /** * Represents the input field of the autocomplete. * * Events on the input field like onChange are defined here. * * @type {{name: string, element: undefined, spinnerElement: undefined, spinnerTemplate: string, showSpinner: showSpinner, hideSpinner: hideSpinner, onChange: onChange, onNonInputKeys: onNonInputKeys, init: init}} */ var input = { name: autocomplete-input, element: undefined, spinnerElement: undefined, spinnerTemplate: '', /** * Shows a small spinner in the input field whenever the service loads data. */ showSpinner: function () { if (input.spinnerElement) { input.spinnerElement.removeCl (hide); events.onSpinnerShow.forEach(function (handler) { handler(); }); } }, /** * Hides the spinner. */ hideSpinner: function () { if (input.spinnerElement) { input.spinnerElement.addCl (hide); events.onSpinnerHide.forEach(function (handler) { handler(); }); } }, /** * This method gets called each time the user input is changed. */ onChange: function () { var value = this.element.val(); events.beforeLoad.forEach(function (handler) { handler(value); }); service.load(value); completions.update(); }, /** * Will handle key up events that should not be handled as input change but as something else. * * @return boolean true if the event was handled, else false */ onNonInputKeys: function (event) { if (event.keyCode === sirius.keys.KEY_ENTER || event.keyCode === sirius.keys.KEY_TAB) { completions.select(completions.selectedRow); return true; } if (event.keyCode === sirius.keys.KEY_ARROW_DOWN) { if (!completions.isVisible()) { completions.show(); } if (completions.selectedRow === undefined) { completions.hoverRow(completions.element.find(.autocomplete-row-js).first()) } else { var nextRow = completions.selectedRow.nextAll(.autocomplete-row-js).first(); if (nextRow.length) { completions.unHoverRow(completions.selectedRow); completions.hoverRow(nextRow); } } return true; } if (event.keyCode === sirius.keys.KEY_ARROW_UP) { if (completions.selectedRow !== undefined) { var prevRow = completions.selectedRow.prevAll(.autocomplete-row-js).first(); completions.unHoverRow(completions.selectedRow); if (prevRow.length) { completions.hoverRow(prevRow); } } else { completions.hideImmediate(); } return true; } if (event.keyCode === sirius.keys.KEY_ESC) { completions.hideImmediate(); return true; } completions.selectedRow = undefined; return false; }, /** * Initializes the input field. * */ init: function (config) { this.element = $(# + this.name); if (config && !config.noSpinner) { input.spinnerElement = $(input.spinnerTemplate); input.spinnerElement.insertAfter(input.element); // this is needed to display the spinner in the same row as the input field // the spinner holds the cl .fa which defines the size to 14 // because jquery width rounds up or down we need to make provisions for these cases using a 2px margin input.element.css(max-width, input.element.width() - 16); } this.element.keyup(function (event) { sirius.keys.enableKeyUpIpadSupport(event); if (input.onNonInputKeys(event) === false) { input.onChange(); } }); this.element.keydown(function (event) { if (!completions.isVisible()) { return; } // disables the default key_arrow_down event (moves cursor after the last char of the input) // and key_arrow_up event (moves cursor before the first char of the input) if (event.keyCode === sirius.keys.KEY_ARROW_UP || event.keyCode === sirius.keys.KEY_ARROW_DOWN) { event.preventDefault(); } }); this.element.focusout(function () { completions.hide(); }); this.element.focusin(function () { completions.show(); }); this.element.click(function () { completions.show(); }); } }; /** * Represents autocomplete suggestions html element. * * Handles the events & actions on the different rows in the element. */ var completions = { element: undefined, selectedRow: undefined, rows: [], rowTemplates: undefined, HIDDEN: 0, VISIBLE: 1, SOON_TO_BE_HIDDEN: 2, state: undefined, config: undefined, /** * Initializes the completions element. * * Keys of the config object are: * - id: the id of the autocomplete wrapper div */ init: function (config) { this.config = config; var wrapper = ; this.state = completions.HIDDEN; this.element = $(Mustache.render(wrapper, config)); this.rePosition(); this.element.on(mouseup.sirius-autocomplete, .autocomplete-row-js, function () { completions.select($(this)); }); $(body).append(this.element); }, rePosition: function () { if (this.config.width) { this.element.width(this.config.width); } else { this.element.width(anchor.element.outerWidth()); } var offset = this.element.offset(); var top = anchor.element.offset().top + anchor.element.outerHeight(); var left = anchor.element.offset().left; if (offset.top !== top || offset.left !== left) { offset.top = top; offset.left = left; this.element.offset(offset); } }, /** * Adds the hoverRow && unHoverRow events to the given autocompletion row. * * @param $row the row element or a child element or a autocompletion row. */ addHoverRowEvent: function ($row) { $row.find(.autocomplete-row-js).hover(function () { completions.hoverRow($row); }, function () { completions.unHoverRow($row); }); if ($row.hasCl (autocomplete-row-js)) { $row.hover(function () { completions.hoverRow($row); }, function () { completions.unHoverRow($row); }); } }, hoverRow: function ($row) { completions.selectedRow = $row; $row.addCl (autocomplete-selected-element); }, unHoverRow: function ($row) { if ($row) { $row.removeCl (autocomplete-selected-element); } completions.selectedRow = undefined; }, setTemplates: function (templates) { if (typeof templates !== object) { throw templates is no object; } this.rowTemplates = templates; }, show: function () { if (this.rows.length > 0 && input.element.is(:focus)) { completions.selectedRow = undefined; this.update(); completions.element.show(); this.state = completions.VISIBLE; events.onShow.forEach(function (handler) { handler(); }); } }, hide: function () { if (completions.state === completions.HIDDEN) { return; } completions.state = completions.SOON_TO_BE_HIDDEN; window.setTimeout(function () { /* * This hack is necessary to allow the click event to be handled before the element is hidden. * * Order of events: * 1. mouseDown * 2. focusOut ( will hide the autocompletion) * 3. click * * The focus check is necessary because the input field could already be focused (again). * In that case the autocomplete should not be hidden. */ if (completions.state === completions.VISIBLE || input.element.is(:focus)) { return; } completions.hideImmediate(); }, 500); }, hideImmediate: function () { if (completions.state === completions.HIDDEN) { return; } completions.state = completions.HIDDEN; completions.unHoverRow(completions.selectedRow); completions.element.hide(); input.hideSpinner(); events.onHide.forEach(function (handler) { handler(); }); }, isVisible: function () { return completions.state === completions.VISIBLE; }, /** * Retrieves the template for the given type. * * @param type string which represents the type name * @returns string representing the template of the given row type */ templateForType: function (type) { if (type && Object.keys(this.rowTemplates).includes(type)) { return this.rowTemplates[type]; } return this.rowTemplates.basic; }, /** * Updates the rows in the autocomplete wrapper */ update: function () { this.element.empty(); if (this.rows.length < 1) { completions.hideImmediate(); return; } $.each(this.rows, function (index, row) { var template = completions.templateForType(row.type); var $row = $(Mustache.render(template, row)); completions.addHoverRowEvent($row); completions.element.append($row); events.afterRenderRow.forEach(function (handler) { handler($row); }); }); events.afterRender.forEach(function (handler) { handler(); }); }, /** * Called if a row of the autocomplete is selected. * * Retrieves the actual row element ociated with the selected $element * and calls events.onSelect(selectedRow). * * Will call events.onSelect() if no valid current row was selected. * * @param $element the element that was selected */ select: function ($element) { var result = false; if (events.onSelect !== undefined) { if ($element) { var selectedElement = $element.closest(.autocomplete-row-js); if (selectedElement.length) { result = events.onSelect(selectedElement); } else { result = events.onSelect(); } } else { result = events.onSelect(); } } if (!result) { completions.hideImmediate(); } } }; var events = { onReady: [], onShow: [], onHide: [], /** * Handle the selection of a row element. * * Allows only one handler. * * @param the selected element, optional * @return true if the result overlay should stay visible, optional */ onSelect: undefined, onSpinnerShow: [], onSpinnerHide: [], beforeLoad: [], /** * Handles the loaded autocompletion data, after a successful request. * * Allows only one handler. * * @param value the autocomplete string value * @param the response of the autocomplete service * @return an array of row objects. */ afterLoad: undefined, afterRenderRow: [], afterRender: [] }; var service = { uri: undefined, minSize: 1, delay: 400, responseCache: {}, lastLoadTriggered: undefined, loading: false, [censored]
|
/nutzungsbedingungen: | |
---|---|
Title |
nutzungsbedingungen - Lottermetall |
Description |
nutzungsbedingungen |
H1 |
Nutzungsbedingungen |
H2 |
{{shortText}} {{itemNumberLabel}}: {{itemNumber}} {{#recommendedPrice}} {{recommendedPrice}} {{/recommendedPrice}} {{effectivePrice}} {{#effectivePriceSuffix}} {{effectivePriceSuffix}} {{/effectivePriceSuffix}} {{#secondaryPrice}} {{secondaryPrice}} {{secondaryPriceSuffix}} {{/secondaryPrice}} {{priceQuantityLabel}} {{priceQuantity}} '; function loadItemText() { var overwriteLongtext = true; var $longtext = $(#output-longtext); if (overwriteLongtext || $longtext.length === 0 || isEmpty($longtext.html().trim())) { loadOxomiItemText(); } } /** * Increments the item quantity by a certain amount * * Uses toFixed to round the result to the right number of decimals to prevent errors due to floating point * arithmetic. * * @param id the ID of the input field to increment * @param orderStep the amount to increment */ function incrementItemQuantity(id, orderStep) { var $input = $('#' + id); var result = parseFloat((parseFloat($input.val()) + orderStep).toFixed(3)); $input.val(result); } /** * Decrements the item quantity by a certain amount * * Uses toFixed to round the result to the right number of decimals to prevent errors due to floating point * arithmetic. * * @param id the ID of the input field to decrement * @param orderStep the amount to decrement * @param minOrderQuantity the minimum order quantity */ function decrementItemQuantity(id, orderStep, minOrderQuantity) { var $input = $('#' + id); var result = parseFloat((parseFloat($input.val()) - orderStep).toFixed(3)); if (result < minOrderQuantity) { $input.val(minOrderQuantity); } else { $input.val(result); } } var IMAGE_OVERLAY_TEMPLATE = '' + ' ' + ' ' + ' {{#images}}' + ' ' + ' ' + ' ' + ' ' + ' ' + ' {{/images}}' + ' ' + ' ' + ' ' + ' ' + ' ' + ''; function createImageOverlay($container) { // Event handler that opens the item image overlay and displays the clicked image var showArrows = true; var fadeIn = false; $container.on('click', 'a', function (e) { e.preventDefault(); var currentUrl = $(this).attr('href'); var currentIndex = 0; var images = []; // Find all item images and the index of the one that was clicked TODO $container.find('.item-image-js').filter(function (index, element) { return !$(element).parent().hasCl ('slick-cloned'); }).each(function (index, element) { var url = $(element).attr('href'); images.push(url); if (url === currentUrl) { currentIndex = index; } }); // Generate and add the overlay to the DOM var $overlay = $(Mustache.render(IMAGE_OVERLAY_TEMPLATE, {'images': images})); var $slider = $overlay.find('.image-overlay-images-js'); $('body').addCl ('image-overlay-open').append($overlay); if (fadeIn) { $overlay.hide().fadeIn(); } // Generate the slider $slider.slick({ slidesToShow: 1, dots: true, arrows: showArrows, initialSlide: currentIndex }); // Event handler for pressing escape, left/right arrow keys var keydownHandler = function (e) { if (e.keyCode === 27) { closeOverlay(); } else if(e.keyCode === 37) { $slider.slick('slickPrev'); } else if(e.keyCode === 39) { $slider.slick('slickNext'); } }; // Function that closes the overlay and removes the escape key event handler var closeOverlay = function (e) { $('body').removeCl ('image-overlay-open'); $overlay.remove(); $(do ent).off('keydown', keydownHandler); }; // Click on the close on closes the overlay $overlay.find('.image-overlay-close').click(function (e) { e.preventDefault(); closeOverlay(); }); // Click on the background closes the overlay $overlay.click(function (e) { if (e.target !== this) { return; } closeOverlay(); }); // Event handler for keyboard inputs $(do ent).keydown(keydownHandler); }); } var AUTOCOMPLETE_SUGGESTION_TEMPLATE = '' + ' {{label}}' + ' {{#isERPAddress}}' + ' ' + ' Nicht veränderbar' + ' ' + ' {{/isERPAddress}}' + ' {{#hasDescription}}' + ' ' + ' {{#descriptionLines}}' + ' {{.}}' + ' {{/descriptionLines}}' + ' ' + ' {{/hasDescription}}' + ''; function enableAutocomplete(field) { function createSubmitData(key, value) { var data = {}; var fieldData = field.data(); for(f in fieldData) { if (fieldData.hasOwnProperty(f)) { if (f != 'autocomplete' && f != 'optional' && f != 'select2') { data[f] = fieldData[f]; } } } data[key] = value; return data; } if (field.data('optional') && field.is(:empty)) { field.prepend(''); } field.on('select2:open', function (e) { $('.select2-search__field').each(function(e) { var search = $(this); if (search.parent().hasCl ('select2-search--inline')) { // Don't add placeholder and graphic to inline search fields return; } search.css({ 'background-image': 'url(/ ets/wondergem/select2/chosen-sprite.png)', 'background-repeat': 'no-repeat', 'background-position': '100% -22px' }); var placeholder = field.attr('data-searchtext'); if (typeof placeholder === 'undefined' || placeholder === '') { placeholder = 'Geben Sie einen Suchtext ein…'; } search.attr('placeholder', placeholder); }); }); field.on('select2:unselect', function(e) { $(this).html(''); e.preventDefault(); e.stopPropagation(); }); field.select2({ allowClear: field.data('optional'), placeholder: 'Ihre Auswahl…', dropdownParent: field.parent(), minimumInputLength: 0, tags: field.data('dynamic-option'), templateResult: function (result) { if (typeof result === 'undefined') { return undefined; } var hasDescription = typeof result.description !== 'undefined' && result.description !== ''; if (field.attr('data-multiline')) { return $(Mustache.render(AUTOCOMPLETE_SUGGESTION_TEMPLATE, { 'label': result.text, 'hasDescription' : hasDescription, 'descriptionLines': hasDescription ? result.description.split(' ') : undefined, 'isERPAddress': isERPAddress(result.id) })); } return hasDescription ? result.description : result.text; }, language : { loadingMore: function() { return 'Lade Daten…'; }, searching: function () { return 'Suche…'; }, noResults: function () { return 'Keine Suchtreffer…'; } }, ajax: { url: '/' + field.data('autocomplete'), dataType: 'jsonp', quietMillis: 100, data: function(term, page) { return createSubmitData('query', term.term); }, processResults: function (data, page) { return { results: data.completions, more: false }; } } }); } function isERPAddress(addressAsJson) { try { return JSON.parse(addressAsJson).isERPAddress; } catch(e) { return undefined; } } $(do ent).ready(function() { $('select[data-autocomplete]').each(function(e) { var field = $(this); enableAutocomplete(field); }); $('.select2-select').each(function(e) { var field = $(this); if (field.data('optional')) { field.prepend(''); } field.select2({ allowClear: field.data('optional'), placeholder: 'Ihre Auswahl…', dropdownParent: field.parent(), minimumResultsForSearch: 10, width : '100%', language : { maximumSelected: function(args) { return 'Sie können maximal ' + args.maximum + ' Elemente auswählen'; }, searching: function () { return 'Suche…'; }, noResults: function () { return 'Keine Suchtreffer…'; } }, escapeMarkup: function(m) { // Do not escape HTML in the select options text return m; } }); }); }); function initializeMEMOIO() { $('').prependTo($('head')); $(do ent).one('memoio-ready', function () { memoio.initSettings({ email: '', name: '', showBadge: 'never' }); $('.memoio-flap').removeCl ('hidden'); }); $('').appendTo($('head')); } /** * Cleans up all MEMOIO settings variables which are set by the integration. * The settings are cleaned up to avoid wrong values being set when calling * different conversations on the same page. */ function cleanupMEMOIOSettings() { memoio.initSettings({ partner: '', silentMessage: '', topic: '', reference: '', skipTopic: false }); } /** * Starts a conversation with the shop's support channel. */ function talkToUs() { return talkToChannel('JA6AT5NFJ1IK0V9DGD9GP6BS74'); } /** * Starts a conversation with the given channel. * * @param channelId the unique id of the channel to talk to */ function talkToChannel(channelId) { chatWithChannel(channelId, '', '', 'Die Anfrage wurde auf der Seite https://lottermetall24.de/nutzungsbedingungen Ihres Shop-Systems gestartet.'); return false; } /** * Starts a conversation with the given mail. * * @param email the email of the person to talk to */ function talkToMail(email) { cleanupMEMOIOSettings(); memoio.initSettings({ partner: 'email:' + email, silentMessage: 'Die Anfrage wurde auf der Seite https://lottermetall24.de/nutzungsbedingungen Ihres Shop-Systems gestartet.' }); memoio.show(); return false; } /** * Starts a conversation with the given person. * * @param personId the unique id of the person to talk to */ function talkToPerson(personId) { chatWithChannel(personId, '', '', 'Die Anfrage wurde auf der Seite https://lottermetall24.de/nutzungsbedingungen Ihres Shop-Systems gestartet.'); return false; } /** * Starts a memoio chat with the person represented by the memoio talkToMeId. * * @param talkToMeId the unique id of the person to talk to * @param topic optional, the topic of the conversation * @param reference optional, multiple references can be set comma separated * @param initialMessage optional, the initial message that is sent, after the chat is started * @param skipTopic optional, if the topic should not be requested from the user */ function chatWithPerson(talkToMeId, topic, reference, initialMessage, skipTopic) { cleanupMEMOIOSettings(); memoio.initSettings({ partner: 'person:' + talkToMeId, topic: topic, reference: reference, silentMessage: initialMessage, skipTopic: skipTopic }); memoio.show(); } /** * Starts a memoio chat with a channel represented by the memoio channelId. * * @param channelId the unique id of the channel to talk to * @param topic optional, the topic of the conversation * @param reference optional, multiple references can be set comma separated * @param initialMessage optional, the initial message that is sent, after the chat is started * @param skipTopic optional, if the topic should not be requested from the user */ function chatWithChannel(channelId, topic, reference, initialMessage, skipTopic) { cleanupMEMOIOSettings(); memoio.initSettings({ partner: 'channel:' + channelId, topic: topic, reference: reference, silentMessage: initialMessage, skipTopic: skipTopic }); memoio.show(); } $(do ent).ready(function () { initializeMEMOIO(); }); /** * Fetches the memoio person information. * * @param talkToMeId to unqiue person id which identifies a memoio contact * @param uniqueId the unique element id */ function getMemoioPersonInformation(talkToMeId, uniqueId) { var uri = https://memoio.com/api/person-info; return jsonRequest(uri, { talkToMeId: talkToMeId }).then(function (json) { var $memoioElement = $(# + uniqueId); var $avatar = $memoioElement.find(.img-js); if (isEmpty(json.avatar)) { $avatar.remove(); } else { $avatar.prop(src, json.avatar); } var $name = $memoioElement.find(.name-js); $name.html(json.name); if (json.status === ACTIVE) { $name.after(''); } $afterName = $name.parent(); if (!isEmpty(json.position)) { $afterName.after(Mustache.render('{{position}}', json)); } if (!isEmpty(json.awayInfo)) { $afterName.after(Mustache.render('{{awayInfo}}', json)); } }).catch(function(){ $(# + uniqueId).remove(); }); } function getChannelInformation(channelId, uniqueId){ var uri = https://memoio.com/api/channel-info; return jsonRequest(uri, { channel: channelId }).then(function (json) { var $memoioElement = $(# + uniqueId); var $avatar = $memoioElement.find(.img-js); if (isEmpty(json.avatar)) { $avatar.remove(); } else { $avatar.prop(src, json.avatar); } var $name = $memoioElement.find(.name-js); $name.html(json.name); if (json.open) { $name.after(''); } $afterName = $name.parent(); if (!isEmpty(json.description)) { $afterName.after(Mustache.render('{{description}}', json)); } if (!isEmpty(json.message)) { $afterName.after(Mustache.render('{{message}}', json)); } }).catch(function(){ $(# + uniqueId).remove(); }); } /** * Retrives Information about known items from shop for Infoplay. */ function infoplayItemLookup(infoplayData, next) { fillSelection(infoplayData); if (infoplayData.isSelectedAlternative) { $.getJSON( '/items/api/infos', { uniqueItemNumber: infoplayData.uniqueItemNumber }, function (json) { if (json.error) { oxomi.showMessageInDialog(Fehler, json.message); } else { infoplayData.items.push(renderInfoplayItem(json.item, infoplayData)); next(infoplayData); } } ); } else { $.getJSON( '/items/api/infoplay', { query: infoplayData.itemNumber, supplierNumber: infoplayData.supplierNumber }, function (json) { if (json.error) { oxomi.showMessageInDialog(Fehler, json.message); } else { for (i = 0; i < json.items.length; i++) { infoplayData.items.push(renderInfoplayItem(json.items[i], infoplayData)); } next(infoplayData); } } ); } } /** * Generates an item object for Infoplay. */ function renderInfoplayItem(item, infoplayData) { var newItem = { itemNumber: item.itemNumber, uniqueItemNumber: item.uniqueItemNumber, itemUrl: '/item/' + item.uniqueItemNumber, supplierName: item.brandName, shortText: item.shortText, previewImageUrl: item.previewImageUrl, quantity: item.minOrderQuantityUser, reresolve: true, features: [] }; var priceString = item.effectivePrice; if (item.hasEffectivePrice) { priceString = priceString + + item.effectivePriceSuffix; } var availability = item.stockText; if (item.additionalStockText) { availability = availability + + item.additionalStockText; } newItem.features.push({ fields: [ {name: item.effectivePriceName, value: priceString}, {name: 'Preismenge', value: item.priceQuantity}, {name: 'Min. Bestellmenge', value: item.minOrderQuantity}, {name: 'Bestellschritt', value: item.orderStep}, {name: 'Verfügbarkeit', value: availability, span: true} ] }); return newItem; } /** * Basket handler for known items in shop via Infoplay. */ function infoplayBasket(infoplayData, next) { var machineQuantity = infoplayData.quantity.replace(/./g, '').replace(',', '.'); addItemToBasket(infoplayData.item.uniqueItemNumber, machineQuantity) .then(function (response) { return infoplaySuccessMessage(response, infoplayData, next); }) .then(refreshBasketInfo) .catch(function (response) { return infoplayErrorMessage(response, infoplayData, next); }); } /** * Safely fills in custom attribute selection in infoplayData * which is needed for div items. */ function fillSelection(infoplayData) { if (!infoplayData.selection) { infoplayData.selection = infoplayData.itemNumber; } } /** * Function to show success message for Infoplay add to basket */ function infoplaySuccessMessage(response, infoplayData, next) { infoplayData.basketMessage = 'Ihr Warenkorb wurde aktualisiert: ' + response.basketInfo; next(infoplayData); return response; } /** * Function to show error message for Infoplay add to basket */ function infoplayErrorMessage(response, infoplayData, next) { infoplayData.basketMessage = response.message; next(infoplayData); return response; } /** * Injects link into Infoplay dialog to request div item. */ function enhanceExternalInfoplay(infoplayData, infoplayExternalLookup, processInfoplayItemResult) { var addDivItemCallback = function (infoplayDataFilled) { fillSelection(infoplayDataFilled); for (i = 0; i < infoplayDataFilled.items.length; i++) { infoplayDataFilled.items[i].features = [linkForDivItem(infoplayDataFilled)]; } processInfoplayItemResult(infoplayDataFilled); }; infoplayExternalLookup(infoplayData, addDivItemCallback); } /** * Handler for adding div items to basket via Infoplay. */ function infoplayExternalBasket(infoplayData, next) { var supplierItem = { supplier: infoplayData.item.supplierName, supplierNumber: infoplayData.supplierNumbers.join(), supplierItemNumber: infoplayData.item.itemNumber, shorttext: infoplayData.item.shortText, quantity: infoplayData.quantity, externalUrl: generateOxomiCatalogUrl(infoplayData), comment: generateCatalogComment(infoplayData), priceQuantity: infoplayData.item.priceQuantity, unitCode: infoplayData.item.quantityUnit } addUserDefinedItemToBasket(supplierItem) .then(function (response) { return infoplaySuccessMessage(response, infoplayData, next); }) .then(refreshBasketInfo) .catch(function (response) { return infoplayErrorMessage(response, infoplayData, next); }); } /** * Template for custom Infoplay dialog to add div item. */ var OXOMI_INFOPLAY_TEMPLATE = '' + ' ' + ' ' + ' Artikelnummer' + ' ' + ' ' + ' ' + ' Hersteller' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ''; /** * Renders custom dialog for div items. */ function renderCustomDialog(infoplayData) { var dialog = $(OXOMI_INFOPLAY_TEMPLATE); var submitFunction = function () { infoplayData.quantity = $(#oxomi-quantity).val(); infoplayData.item = { itemNumber: $(#oxomi-itemNumber).val(), supplierName: $(#oxomi-supplier).val() }; infoplayExternalBasket(infoplayData, function (infoplayData) { oxomi.showMessageInDialog($('#oxomi-dialog-title').text(), infoplayData.basketMessage); }); }; $('#oxomi-add-to-basket', dialog).click(submitFunction); $('#oxomi-quantity', dialog).keypress(function (e) { if (e.which == 13) { submitFunction(); } }); $(#oxomi-supplier, dialog).val(infoplayData.brandName); $(#oxomi-itemNumber, dialog).val(infoplayData.selection); oxomi.fillDialog('Diversartikel erf en', dialog); } /** * Adds link to request a div item with logic to add the item to basket. */ function linkForDivItem(infoplayData) { return { title: 'Diversartikel', fields: [{ value: $('Nicht der p ende Artikel? Hier Diversartikel anfragen').click(function () { renderCustomDialog(infoplayData); }), span: true }] }; } /** * Template for catalog URL in div item infos. */ var OXOMI_CATALOG_URL_TEMPLATE = 'https://oxomi.com/p/1554493/catalog/{{catalogId}}?page={{pageNum}}&query={{query}}'; /** * Generates URL from which catalog the item was requested. */ function generateOxomiCatalogUrl(infoplayData) { return Mustache.render(OXOMI_CATALOG_URL_TEMPLATE, { catalogId: infoplayData.catalogId, pageNum: infoplayData.pageNum, query: encodeURIComponent(infoplayData.selection) }); } /** * Generates comment for catalog information. */ function generateCatalogComment(infoplayData) { var commentString = ; if (typeof infoplayData.catalogName != 'undefined') { commentString = Mustache.render('Aus {{catalogName}} (Seite {{visiblePageNum}}) von {{brandName}}', { catalogName: infoplayData.catalogName, visiblePageNum: infoplayData.visiblePageNum, brandName: infoplayData.brandName }); } return commentString; } /** * Renders div item if no item was found in shop and OXOMI. */ function infoplayEmptyResult(infoplayData, next) { fillSelection(infoplayData); renderCustomDialog(infoplayData); oxomi.showDialog(); } setTimeout(function () { var script = do ent.createElement(script); script.type = text/ ascript; script.src = https://oxomi.com/ ets/frontend/oxomi.js do ent.getElementsByTagName(head)[0].appendChild(script); }, 0); function oxomi_ready() { var settings = { server: 'https://oxomi.com', portal: '1554493', infoplayItemLookup: infoplayItemLookup, infoplayMenuTitle: 'Zum Warenkorb hinzufügen...' }; oxomi.init(settings); } // don't do a code format in here: this would mess up everything $(do ent).ready(function () { }); var BASKET_DISCOUNT_HEADER_TEMPLATE = '' + ' ' + ' ' + ' {{discountProgressText}}' + ' ' + ' ' + ' {{#barStatus}}' + ' ' + ' {{/barStatus}}' + ' ' + ' '; var ITEM_PRICE_SCALE_TABLE_ENTRY_TEMPLATE = '' + ' {{scaleDescription}}' + ' ' + ' ' + ' Menge übernehmen' + ' ' + ' ' + ' ' + ' {{scalePrice}}' + ' je {{priceQuantity}}' + ' ' + ''; function clearMessages() { $(#messageBox).hide() $(#messageBox).empty(); } function hasMessage() { return !($(#messageBox).css('display') == 'none'); } function addMessage(type, message, action, actionLabel, details) { var completeMessage = message; if (!isEmpty(actionLabel) && $.isFunction(action)) { completeMessage += '' + actionLabel + ''; } else if (!isEmpty(actionLabel)) { completeMessage += ' ' + actionLabel + ''; } if (details == persistent) { addPersistentMessage(type, message, action, actionLabel); } else { notify(type, completeMessage); } } function notify(type, message) { var $notify = $.notify({ // options message: message, icon: 'fa fa-check-circle-o' }, { // settings type: type, offset: { x: 0, y: 0 }, placement: { from: 'top', align: 'center' }, newest_on_top: true, animate: { enter: 'animated slideInDown', exit: 'animated slideOutUp' }, template: '' + '' + ' ' + '{1}' + '{2}' + '' }); $messages.push($notify); } /** * Pushes the Footer to the bottom of the viewport */ function calcContentHeight() { var newHeight = $(window).height() - $('.footer').outerHeight(true); $('.wrapper-js').css('min-height', newHeight + 'px'); } $(do ent).ready(function (e) { $(window).resize(calcContentHeight); calcContentHeight(); }); /** * Calculates content container height to make sure sidebar-filter is long enough */ function calcSidebarHeight() { var newSidebarHeight = $(window).height() - $('.footer').outerHeight(true) - $('.header').outerHeight(true); $('.sidebar-filter-js').css('min-height', newSidebarHeight + 'px'); } $(window).load(function () { $(window).resize(calcSidebarHeight); calcSidebarHeight(); }); /** * Shows success message for basket refresh */ function showBasketSuccessMessage(response) { addMessage(page-alert alert-success, response.message, /basket, 'Warenkorb anzeigen'); return response; } function fileUpload(url, target, params, allowedExtensions) { var container = target; new qq.FileUploader({ element: target, action: url, params: params, debug: false, onComplete: function (cmp_id, fileName, responseJSON) { clearMessages(); // the basket file uploader overwrites the normal file uploader logic if (responseJSON.basketUploadHandling) { handleBasketFileUploaderResponse(responseJSON); return; } // the customer item numbers uploader needs to be handled differently if (!isEmpty(responseJSON.redirectUri)) { loadUrl(responseJSON.redirectUri); return; } // default handling handleDefaultFileUploaderResponse(responseJSON); }, showMessage: function (message) { // We generally send a flag error which is true or false as // part of the response. Sadly, fileUploader.js checks for this // flag (expecting a string) and invokes showMessage is present. // Therefore we have to filter this here :-/ if (message !== true) { clearMessages(); addError(message); } }, messages: { typeError: 'Ungültiger Dateityp', sizeError: 'Datei zu groß', minSizeError: 'Datei zu klein', emptyError: 'Datei ist leer' }, allowedExtensions: allowedExtensions, template: '' + 'Ziehen Sie Dateien hierher, um diese hochzuladen…' + 'Datei auswählen…' + '' + '', fileTemplate: '' + '' + '' + '' + 'Abbrechen' + 'Upload fehlgeschlagen' + '' }); } function addInfo(message, action, actionLabel) { if (action) { $('' + message + ' ' + actionLabel + '').appendTo($('#messageBox')); } else { $('').html(message).appendTo($('#messageBox')); } } function addError(message) { $('').html(message).appendTo($('#messageBox')); } /** * Refreshes the basket info in the header section */ function refreshBasketInfo(response) { $('.header-basket-sum-js').html( + response.basketPrice + ); $('.header-basket-badge-js').text(response.basketPositions); if (response.showBasketDiscountBar) { $('.basket-discount-header-wrapper').removeCl ('hide'); $('.basket-discount-header-wrapper').html(Mustache.render(BASKET_DISCOUNT_HEADER_TEMPLATE, { discountProgressText: response.discountProgressText, barStatus: response.barStatus })); } else { $('.basket-discount-header-wrapper').addCl ('hide'); } return response; } /** * A file uploaded to the basketUploader requires a special response handling. */ function handleBasketFileUploaderResponse(responseJSON) { if (responseJSON.error) { addError(responseJSON.message); } else if (responseJSON.success) { showBasketSuccessMessage(responseJSON); refreshBasketInfoAsync(responseJSON); if (responseJSON.warning) { addWarningMessage(responseJSON.warningMessage); } } $(#messageBox).show(); } /** * The json response handling for customer item number uploads in the frontend. */ function handleCustomerItemNumbersUploaderResponse(responseJSON) { loadUrl(/settings/customer-item-numbers); } /** * The default json response handling for file uploads in the frontend. */ function handleDefaultFileUploaderResponse(responseJSON) { if (responseJSON.error) { addError(responseJSON.message); } else if (responseJSON.success) { if (responseJSON.message) { addSuccessMessage(responseJSON.message); } if (responseJSON.warning) { addWarningMessage(responseJSON.warningMessage); } if (responseJSON.errorDetails) { addInfo(responseJSON.errorDetails); } } $(#messageBox).show(); } /** * Adds all items to the basket with the given quantity. * * Searches for d:textfields within the given jquery $element. * Expects the id to be the uniqueItemNumber and the wanted quantity the value of the textfield. * * Will ignore textfields with an empty value. * * @param $element the jquery element containing the textfields */ function addAllToBasket($element) { waitForLoadedToAddItems($element); } function waitForLoadedToAddItems($element) { var waited = false; $element.find(input[type=number]).each(function () { if (isEmpty($(this).val())) { return; } var $parent = $(this).parent().parent(); if ($parent.data(loaded)) { return; } waited = true; showLoadingSpinner(); if (!$parent.data(load-running)) { loadTooltip($parent.data(identifier), $parent.data(item-number), undefined, true); } }); if (!waited) { addMultipleMatrixItems(fetchMatrixPositions($element)); return; } setTimeout(function () { waitForLoadedToAddItems($element); }, 200) } function fetchMatrixPositions($element){ var matrixPositions = []; $element.find(input[type=number]).each(function () { var item = { quantity: $(this).val(), uniqueItemNumber: $(this).attr(name), itemNumber: $(this).parent().parent().data(item-number) }; if (!isEmpty(item.quantity)) { matrixPositions.push(item); } $(this).val(); }); return matrixPositions; } function addMultipleMatrixItems(matrixPositions) { if (matrixPositions.length === 0) { return; } postJSONContent(/api/basket/add-multiple-matrix-items, { positions: matrixPositions }, false, true) .then(function (response) { if (response.missed) { addErrorMessage(response.message); } else { showBasketSuccessMessage(response); } return response; }) .then(refreshBasketInfoAsync) .catch(showBasketErrorMessage); } /** * Loads the tooltip information by requesting the needed information from the server. * * Tooltip information of an item containing the short text, price and some other information. * Will only load the information once for each element. * * @param elementId the unique id used to identify the tooltip element * @param itemNumber of the item the information is requested for. * @param event the event triggering this function * @param hideTooltip if true the request is fired, but the popover element is not shown */ function loadTooltip(elementId, itemNumber, event, hideTooltip) { var stockInfo = + {{stockText}} var description = {{shortText}}; var priceInformation = 'Mein Preis {{effectivePriceSuffix}}: {{effectivePrice}} (je {{priceQuantity}})'; priceInformation += 'Mindestbestellmenge: {{minOrderQuantity}}'; priceInformation += 'Bestellschritt: {{orderStep}}'; var additionalFeatureInfos = '{{#additionalFeatureInfos}}{{featureName}}: {{featureText}}{{/additionalFeatureInfos}}'; // the actual logic starts here var element = $('#tooltip-' + elementId); if (element.data(loaded) === true) { return; } var itemInput = $(#item- + elementId); element.data(load-running, true); jsonRequest(/items/api/tooltip, {itemNumber: itemNumber}).then(function (json) { if (event !== undefined && $(event.target).is(a)) { loadUrl(/item/ + json.uniqueItemNumber); return; } element.data(loaded, true); element.data(load-running, false); if (!hideTooltip) { element.data(bs.popover).options.content = Mustache.render(description + stockInfo + priceInformation + additionalFeatureInfos, json); element.data(bs.popover).setContent(); element.popover(hide); element.popover(show); } $(#item-link- + elementId).attr(href, /item/ + json.uniqueItemNumber); itemInput.attr(name, json.uniqueItemNumber); }).catch(function (json) { element.data(loaded, true); element.data(load-running, false); element.data(bs.popover).options.content = json.message; element.data(bs.popover).setContent(); element.popover(hide); element.popover(show); itemInput.attr(readonly, readonly); itemInput.val(); $(#item-link- + elementId).html(itemNumber + ' (Nicht vorhanden)'); }); } /** * Initializes all tooltip elements on the given page. */ function initializeTooltips() { $(.small-magic-item-box-js).each(function () { var uniqueId = $(this).data(identifier); var itemNumber = $(this).data(item-number); $(this).click(function (e) { loadTooltip(uniqueId, itemNumber, e); }); $(this).popover({ html: true, trigger: focus, placement: auto top, title: function () { return 'Artikel: ' + itemNumber; }, content: function () { return 'Anfrage läuft...'; } }); }); } $(do ent).ready(function () { initializeTooltips(); }); function submitSearchForRangeFilter() { $(#searchFieldForm).submit(); } /** * Shows a loading spinner */ function showLoadingSpinner() { $(body).css(cursor, wait); } /** * Hides a previously shown loading spinner */ function hideLoadingSpinner() { $(body).css(cursor, default); } /** * polyfill for the date.now method * see: https://developer.mozilla.org/de/docs/Web/ aScript/Reference/Global_Objects/Date/now */ if (!Date.now) { Date.now = function now() { return new Date().getTime(); }; } /** * polyfill for the array.includes method * see https://developer.mozilla.org/de/docs/Web/ aScript/Reference/Global_Objects/Array/includes */ if (!Array.prototype.includes) { Array.prototype.includes = function (searchElement /*, fromIndex*/) { 'use strict'; if (this == null) { throw new TypeError('Array.prototype.includes called on null or undefined'); } var O = Object(this); var len = parseInt(O.length, 10) || 0; if (len === 0) { return false; } var n = parseInt(arguments[1], 10) || 0; var k; if (n >= 0) { k = n; } else { k = len + n; if (k < 0) { k = 0; } } var currentElement; while (k < len) { currentElement = O[k]; if (searchElement === currentElement || (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN return true; } k++; } return false; }; } /** * Polyfill for the String.startsWith function * see https://developer.mozilla.org/de/docs/Web/ aScript/Reference/Global_Objects/String/startsWith#Polyfill */ if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position) { position = position || 0; return this.indexOf(searchString, position) === position; }; } /** * Polyfill for the String.endsWith function * see https://developer.mozilla.org/de/docs/Web/ aScript/Reference/Global_Objects/String/endsWith */ if (!String.prototype.endsWith) { String.prototype.endsWith = function(searchString, position) { var subjectString = this.toString(); if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { position = subjectString.length; } position -= searchString.length; var lastIndex = subjectString.indexOf(searchString, position); return lastIndex !== -1 && lastIndex === position; }; } window.sirius = window.sirius || {}; function asFunction(possibleFunction) { return typeof possibleFunction === function ? possibleFunction : Function(); } /** * Bundles some functions and constants for jquery press key events. */ sirius.keys = (function () { // fix physical keyboard bug on iPad that returns keyCode 0 on keyup var ipadFixMap = { Backspace: 8, Tab: 9, Enter: 13, Control: 17, Escape: 27, : 32, ArrowUp: 38, ArrowDown: 40, ,: 188 }; /** * Holds information about all pressed keys. * * If a key is pressed pressedKeys[keyCode] is set to true, else false. * If the key was never pressed at all pressedKeys[keyCode] is undefined */ var pressedKeys = {}; var events = { keyDown: [], keyUp: [] }; return { KEY_BACKSPACE: 8, KEY_TAB: 9, KEY_ENTER: 13, KEY_SHIFT: 16, KEY_ESC: 27, KEY_ARROW_UP: 38, KEY_ARROW_DOWN: 40, KEY_SEMICOLON: 186, KEY_COMMA: 188, eventNames: function () { return Object.keys(events); }, /** * Adds event handlers. * * @param name of the event * @param callback the function to be executed if the event is triggered */ on: function (name, callback) { if (this.eventNames().includes(name)) { events[name].push(asFunction(callback)); } else { throw Callback + name + is no valid event.; } }, /** * Unbinds one or all event handlers. * * @param name of the event * @param callback the function to unbind, if left empty all handlers are removed */ off: function (name, callback) { if (!this.eventNames().includes(name)) { throw Callback + name + is no valid event.; } if (callback === undefined) { events[name] = []; return; } var remainingHandlers = events[name].filter(function (value) { return value !== asFunction(callback); }); events[name] = remainingHandlers; }, enableKeyUpIpadSupport: function (event) { if (event.keyCode === 0 && event.key) { event.keyCode = event.which = ipadFixMap[event.key]; } }, enableInternetExplorer: function (e) { return e || event; }, /** * Helper method which will call all browser & event specific helper functions. */ browserFixes: function (e) { e = this.enableInternetExplorer(e); this.enableKeyUpIpadSupport(e); return e; }, /** * Register event listeners to detect multiple pressed keys * * every pressed key is saved within the map object * to detected if a key is pressed simple check for map[$keyCode] * * @param $element which should listen to the key down / key up events * @return object of pressed key */ registerMultipleKeyListener: function ($element) { $element.on(keydown.sirius-keys, function (e) { e = sirius.keys.browserFixes(e); pressedKeys[e.keyCode] = true; events.keyDown.forEach(function (handler) { handler(e); }); }); $element.on(keyup.sirius-keys, function (e) { e = sirius.keys.browserFixes(e); pressedKeys[e.keyCode] = false; events.keyUp.forEach(function (handler) { handler(e); }); }); }, /** * Checks if one or multiple keyCodes are pressed. * * This method can be used to check for custom defined short cuts (e.g. shift and enter). * * @param keyCodes can be a string representation of the keyCode or an array of strings * @return {boolean} true if all requested keyCodes are pressed, false otherwise */ isPressed: function (keyCodes) { if (typeof keyCodes !== object) { return pressedKeys[keyCodes] || false; } var allKeysPressed = true; $.each(keyCodes, function (index, keyCode) { if (pressedKeys[keyCode] !== true) { allKeysPressed = false; return false; } }); return allKeysPressed; } } }()); window.sirius = window.sirius || {}; function asFunction(possibleFunction) { return typeof possibleFunction === function ? possibleFunction : Function(); } sirius.createAutocomplete = (function () { /** * Small object which defines some properties (width & position) of the completion div. * * The anchor can be the same as the input field but it is not necessary. * @type {{name: string, element: undefined, init: init}} */ var anchor = { name: autocomplete-anchor, element: undefined, init: function (name) { if (name !== undefined) { this.name = name; } this.element = $(# + this.name); if (!this.element.length) { throw Anchor does not exist } } }; /** * Represents the input field of the autocomplete. * * Events on the input field like onChange are defined here. * * @type {{name: string, element: undefined, spinnerElement: undefined, spinnerTemplate: string, showSpinner: showSpinner, hideSpinner: hideSpinner, onChange: onChange, onNonInputKeys: onNonInputKeys, init: init}} */ var input = { name: autocomplete-input, element: undefined, spinnerElement: undefined, spinnerTemplate: '', /** * Shows a small spinner in the input field whenever the service loads data. */ showSpinner: function () { if (input.spinnerElement) { input.spinnerElement.removeCl (hide); events.onSpinnerShow.forEach(function (handler) { handler(); }); } }, /** * Hides the spinner. */ hideSpinner: function () { if (input.spinnerElement) { input.spinnerElement.addCl (hide); events.onSpinnerHide.forEach(function (handler) { handler(); }); } }, /** * This method gets called each time the user input is changed. */ onChange: function () { var value = this.element.val(); events.beforeLoad.forEach(function (handler) { handler(value); }); service.load(value); completions.update(); }, /** * Will handle key up events that should not be handled as input change but as something else. * * @return boolean true if the event was handled, else false */ onNonInputKeys: function (event) { if (event.keyCode === sirius.keys.KEY_ENTER || event.keyCode === sirius.keys.KEY_TAB) { completions.select(completions.selectedRow); return true; } if (event.keyCode === sirius.keys.KEY_ARROW_DOWN) { if (!completions.isVisible()) { completions.show(); } if (completions.selectedRow === undefined) { completions.hoverRow(completions.element.find(.autocomplete-row-js).first()) } else { var nextRow = completions.selectedRow.nextAll(.autocomplete-row-js).first(); if (nextRow.length) { completions.unHoverRow(completions.selectedRow); completions.hoverRow(nextRow); } } return true; } if (event.keyCode === sirius.keys.KEY_ARROW_UP) { if (completions.selectedRow !== undefined) { var prevRow = completions.selectedRow.prevAll(.autocomplete-row-js).first(); completions.unHoverRow(completions.selectedRow); if (prevRow.length) { completions.hoverRow(prevRow); } } else { completions.hideImmediate(); } return true; } if (event.keyCode === sirius.keys.KEY_ESC) { completions.hideImmediate(); return true; } completions.selectedRow = undefined; return false; }, /** * Initializes the input field. * */ init: function (config) { this.element = $(# + this.name); if (config && !config.noSpinner) { input.spinnerElement = $(input.spinnerTemplate); input.spinnerElement.insertAfter(input.element); // this is needed to display the spinner in the same row as the input field // the spinner holds the cl .fa which defines the size to 14 // because jquery width rounds up or down we need to make provisions for these cases using a 2px margin input.element.css(max-width, input.element.width() - 16); } this.element.keyup(function (event) { sirius.keys.enableKeyUpIpadSupport(event); if (input.onNonInputKeys(event) === false) { input.onChange(); } }); this.element.keydown(function (event) { if (!completions.isVisible()) { return; } // disables the default key_arrow_down event (moves cursor after the last char of the input) // and key_arrow_up event (moves cursor before the first char of the input) if (event.keyCode === sirius.keys.KEY_ARROW_UP || event.keyCode === sirius.keys.KEY_ARROW_DOWN) { event.preventDefault(); } }); this.element.focusout(function () { completions.hide(); }); this.element.focusin(function () { completions.show(); }); this.element.click(function () { completions.show(); }); } }; /** * Represents autocomplete suggestions html element. * * Handles the events & actions on the different rows in the element. */ var completions = { element: undefined, selectedRow: undefined, rows: [], rowTemplates: undefined, HIDDEN: 0, VISIBLE: 1, SOON_TO_BE_HIDDEN: 2, state: undefined, config: undefined, /** * Initializes the completions element. * * Keys of the config object are: * - id: the id of the autocomplete wrapper div */ init: function (config) { this.config = config; var wrapper = ; this.state = completions.HIDDEN; this.element = $(Mustache.render(wrapper, config)); this.rePosition(); this.element.on(mouseup.sirius-autocomplete, .autocomplete-row-js, function () { completions.select($(this)); }); $(body).append(this.element); }, rePosition: function () { if (this.config.width) { this.element.width(this.config.width); } else { this.element.width(anchor.element.outerWidth()); } var offset = this.element.offset(); var top = anchor.element.offset().top + anchor.element.outerHeight(); var left = anchor.element.offset().left; if (offset.top !== top || offset.left !== left) { offset.top = top; offset.left = left; this.element.offset(offset); } }, /** * Adds the hoverRow && unHoverRow events to the given autocompletion row. * * @param $row the row element or a child element or a autocompletion row. */ addHoverRowEvent: function ($row) { $row.find(.autocomplete-row-js).hover(function () { completions.hoverRow($row); }, function () { completions.unHoverRow($row); }); if ($row.hasCl (autocomplete-row-js)) { $row.hover(function () { completions.hoverRow($row); }, function () { completions.unHoverRow($row); }); } }, hoverRow: function ($row) { completions.selectedRow = $row; $row.addCl (autocomplete-selected-element); }, unHoverRow: function ($row) { if ($row) { $row.removeCl (autocomplete-selected-element); } completions.selectedRow = undefined; }, setTemplates: function (templates) { if (typeof templates !== object) { throw templates is no object; } this.rowTemplates = templates; }, show: function () { if (this.rows.length > 0 && input.element.is(:focus)) { completions.selectedRow = undefined; this.update(); completions.element.show(); this.state = completions.VISIBLE; events.onShow.forEach(function (handler) { handler(); }); } }, hide: function () { if (completions.state === completions.HIDDEN) { return; } completions.state = completions.SOON_TO_BE_HIDDEN; window.setTimeout(function () { /* * This hack is necessary to allow the click event to be handled before the element is hidden. * * Order of events: * 1. mouseDown * 2. focusOut ( will hide the autocompletion) * 3. click * * The focus check is necessary because the input field could already be focused (again). * In that case the autocomplete should not be hidden. */ if (completions.state === completions.VISIBLE || input.element.is(:focus)) { return; } completions.hideImmediate(); }, 500); }, hideImmediate: function () { if (completions.state === completions.HIDDEN) { return; } completions.state = completions.HIDDEN; completions.unHoverRow(completions.selectedRow); completions.element.hide(); input.hideSpinner(); events.onHide.forEach(function (handler) { handler(); }); }, isVisible: function () { return completions.state === completions.VISIBLE; }, /** * Retrieves the template for the given type. * * @param type string which represents the type name * @returns string representing the template of the given row type */ templateForType: function (type) { if (type && Object.keys(this.rowTemplates).includes(type)) { return this.rowTemplates[type]; } return this.rowTemplates.basic; }, /** * Updates the rows in the autocomplete wrapper */ update: function () { this.element.empty(); if (this.rows.length < 1) { completions.hideImmediate(); return; } $.each(this.rows, function (index, row) { var template = completions.templateForType(row.type); var $row = $(Mustache.render(template, row)); completions.addHoverRowEvent($row); completions.element.append($row); events.afterRenderRow.forEach(function (handler) { handler($row); }); }); events.afterRender.forEach(function (handler) { handler(); }); }, /** * Called if a row of the autocomplete is selected. * * Retrieves the actual row element ociated with the selected $element * and calls events.onSelect(selectedRow). * * Will call events.onSelect() if no valid current row was selected. * * @param $element the element that was selected */ select: function ($element) { var result = false; if (events.onSelect !== undefined) { if ($element) { var selectedElement = $element.closest(.autocomplete-row-js); if (selectedElement.length) { result = events.onSelect(selectedElement); } else { result = events.onSelect(); } } else { result = events.onSelect(); } } if (!result) { completions.hideImmediate(); } } }; var events = { onReady: [], onShow: [], onHide: [], /** * Handle the selection of a row element. * * Allows only one handler. * * @param the selected element, optional * @return true if the result overlay should stay visible, optional */ onSelect: undefined, onSpinnerShow: [], onSpinnerHide: [], beforeLoad: [], /** * Handles the loaded autocompletion data, after a successful request. * * Allows only one handler. * * @param value the autocomplete string value * @param the response of the autocomplete service * @return an array of row objects. */ afterLoad: undefined, afterRenderRow: [], afterRender: [] }; var service = { uri: undefined, minSize: 1, delay: 400, responseCache: {}, lastLoadTriggered: undefined, loading: false, /** [censored]
|
Similar domain names
lottermo.comlottermoser.comlotternj.comlottermart.comlottermanterrs.comlottermanphc.com
You took 89.95 and 84.95 at the same time from my back account that i didnt authorize and was apparently hacked. I...