Файловый менеджер - Редактировать - /home/digilove/public_html/administrator/components/com_jmap/js/metainfo.js
Назад
/** * Meta info manager * * @package JMAP::METAINFO::administrator::components::com_jmap * @subpackage js * @author Joomla! Extensions Store * @copyright (C) 2021 Joomla! Extensions Store * @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html */ //'use strict'; (function($) { var Metainfo = function() { /** * Target sitemap link * * @access private * @var String */ var targetSitemapLink = null; /** * Message timeout handler * * @access private * @var Object */ var msgTimeout = null; /** * Promises array * * @access private * @var Array */ var promisesCollection = new Array(); /** * Promises array collection for saving multiple records * * @access private * @var Array */ var savePromisesCollection = new Array(); /** * Max title length on desktop * * @access private * @var Integer */ var maxLengthTitleDesktop = 573; /** * Max description length on desktop * * @access private * @var Integer */ var maxLengthDescriptionDesktop = 930; /** * Max title length on mobile * * @access private * @var Integer */ var maxLengthTitleMobile = 550; /** * Max description length on mobile * * @access private * @var Integer */ var maxLengthDescriptionMobile = 905; /** * Title font on desktop * * @access private * @var String */ var titleFontDesktop = '20px Arial,sans-serif'; /** * Description font on desktop * * @access private * @var String */ var descriptionFontDesktop = '14px Arial,sans-serif'; /** * Title font on mobile * * @access private * @var String */ var titleFontMobile = '16px Roboto'; /** * Description font on mobile * * @access private * @var String */ var descriptionFontMobile = '14px Roboto'; /** * Bind the media popovers to images for FB debugger * * @access private * @param String selector * @return void */ var bindMediaPopovers = function(selector) { setTimeout(function(){ $(selector).each(function(index, element){ var $element = $(element); if($element.next('input').val() != '') { $element.attr('data-original-title', COM_JMAP_OPEN_FB_DEBUGGER); } }); }, 1); }; /** * Open first operation progress bar * * @access private * @return void */ var showMessages = function(message, state) { var messageSnippet = '<div id="jmap_alert_message" class="alert alert-' + state + '">' + '<span class="glyphicon glyphicon-info-sign"></span><span class="alert-message"> ' + message + '</span>' + '</div>'; clearTimeout(msgTimeout); $('#jmap_alert_message').remove(); $('#alert_append').append(messageSnippet); $('#jmap_alert_message').fadeIn('fast'); var timerReady = $.Deferred(); $.when(timerReady).done(function(response){ $('#jmap_alert_message').fadeOut('fast', function(){ $('#jmap_alert_message').remove(); }); }); msgTimeout = setTimeout(function(){ timerReady.resolve(); }, 3000); }; /** * Parse url to grab query string params to post to server side for sitemap generation * * @access private * @return Object */ var parseURL = function(url) { var a = document.createElement('a'); a.href = url; return { source: url, protocol: a.protocol.replace(':',''), host: a.hostname, port: a.port, query: a.search, params: (function(){ var ret = {}, seg = a.search.replace(/^\?/,'').split('&'), len = seg.length, i = 0, s; for (;i<len;i++) { if (!seg[i]) { continue; } s = seg[i].split('='); ret[s[0]] = s[1]; } return ret; })(), file: (a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1], hash: a.hash.replace('#',''), path: a.pathname.replace(/^([^\/])/,'/$1'), relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [,''])[1], segments: a.pathname.replace(/^\//,'').split('/') }; } /** * Register user events for interface controls * * @access private * @param Boolean initialize * @return Void */ var addListeners = function(initialize) { // Start the generation process, first operation is enter the progress modal mode $('a.jmap_metainfo').on('click.metainfo', function(jqEvent){ // Prevent click link default jqEvent.preventDefault(); // Show striped progress started generation showProgress(true, 50, 'striped', COM_JMAP_METAINFO_STARTED_SITEMAP_GENERATION); // Grab targeted sitemap link targetSitemapLink = $(this).attr('href'); }); // Register form submit event $('#adminForm ul.pagination-list li').filter(function(){ if($(this).hasClass('active') || $(this).hasClass('disabled')) { return false; } return true; }).on('click.metainfo', function(jqEvent){ // Show striped progress started generation showProgress(true, 100, 'striped', COM_JMAP_METAINFO_ANALYZING_LINKS); }); $('#limit').on('change.metainfo', function(jqEvent){ showProgress(true, 100, 'striped', COM_JMAP_METAINFO_ANALYZING_LINKS); }); $('#adminForm table.adminlist th a.hasTooltip').on('click.metainfo', function(jqEvent){ // Show striped progress started generation showProgress(true, 100, 'striped', COM_JMAP_METAINFO_ANALYZING_LINKS); }); // Register button task actions // Save metainfo $('#adminForm button[data-action=savemeta]').on('click.metainfo', function(jqEvent) { // Prevent button default jqEvent.preventDefault(); // Retrive information to save var rowIdentifier = $(this).data('save'); var linkIdentifier = $('a[data-linkidentifier=' + rowIdentifier + ']').attr('href'); var metaTitle = $('textarea[data-titleidentifier=' + rowIdentifier + ']').val(); var metaDesc = $('textarea[data-descidentifier=' + rowIdentifier + ']').val(); var metaImage = $('input[data-mediaidentifier=' + rowIdentifier + '], #jform_media_identifier_' + rowIdentifier).val(); var robotsDirective = $('select[data-robotsidentifier=' + rowIdentifier + ']').val(); var publishedStatus = $('input[name=published' + (rowIdentifier-1) + ']:checked').prop('value'); var excludedStatus = $('input[name=excluded' + (rowIdentifier-1) + ']:checked').prop('value'); // Perform validation, at least one of title/desc/robots // must be a valid value if (!metaTitle && !metaDesc && !robotsDirective && !metaImage) { showMessages(COM_JMAP_METAINFO_SET_ATLEAST_ONE, 'warning'); return false; } // Now build the object to send to server endpoint var dataObject = { linkurl : linkIdentifier, meta_title : metaTitle, meta_desc : metaDesc, meta_image : metaImage, robots : robotsDirective, published : publishedStatus, excluded : excludedStatus }; // Now save to server side saveDataStatus('saveMeta', dataObject, rowIdentifier); return false; }); // Delete metainfo record $('#adminForm button[data-action=deletemeta]').on('click.metainfo', function(jqEvent) { // Prevent button default jqEvent.preventDefault(); // Retrive information to save var rowIdentifier = $(this).data('delete'); var linkIdentifier = $('a[data-linkidentifier=' + rowIdentifier + ']').attr('href'); // Now build the object to send to server endpoint var dataObject = { linkurl : linkIdentifier }; // Now save to server side saveDataStatus('deleteMeta', dataObject); // Now reset row data var parentRow = $(this).parents('tr'); $('textarea.metainfo, select.robots_directive, input.mediaimagefield', parentRow).val(''); $('textarea.metainfo', parentRow).text(''); rowButtonStatus(parentRow); // Now reset characters counter $('span.labelmetainfo span.jmap_metainfo_counter', parentRow).text(0); $('span.labelmetainfo span.jmap_metainfo_counter_pixel', parentRow).text('0px'); // Reset also a possible danger class $('span.labelmetainfo', parentRow).removeClass('label-danger').addClass('label-primary'); // Finally reset the exclude state in the case there was one. Take care that the record is completely deleted $('fieldset[data-action=excludedmeta] div.controls label:first-child', parentRow).trigger('click', [true]); return false; }); // Change metainfo record state $('#adminForm fieldset[data-action=statemeta] label').on('click.metainfo', function(jqEvent, noTrigger) { // Avoid triggering if not user click if(noTrigger || jqEvent.target.nodeName == 'INPUT') { return true; } // Retrive information to save var rowIdentifier = $(this).parents('fieldset').data('state'); var linkIdentifier = $('a[data-linkidentifier=' + rowIdentifier + ']').attr('href'); var publishedState = $(this).children('input').val(); // Now build the object to send to server endpoint var dataObject = { linkurl : linkIdentifier, field : 'published', fieldValue : parseInt(publishedState) }; // Now save to server side saveDataStatus('stateMeta', dataObject); return true; }); $('#adminForm fieldset[data-action=excludedmeta] label').on('click.metainfo', function(jqEvent, noTrigger) { // Avoid triggering if not user click if(noTrigger || jqEvent.target.nodeName == 'INPUT') { return true; } // Retrive information to save var parentRow = $(this).parents('tr'); var rowIdentifier = $(this).parents('fieldset').data('state'); var linkIdentifier = $('a[data-linkidentifier=' + rowIdentifier + ']').attr('href'); var excludedState = $(this).children('input').val(); // Now build the object to send to server endpoint var dataObject = { linkurl : linkIdentifier, field : 'excluded', fieldValue : parseInt(excludedState) }; // Now save to server side saveDataStatus('stateMeta', dataObject); // Switch by default to unpublished if it's a new empty record store if($('fieldset[data-action=statemeta] div.controls label:first-child', parentRow).hasClass('jmap_inactive')) { $('fieldset[data-action=statemeta] div.controls label:first-child', parentRow).trigger('click', [true]); } return true; }); // Generate metainfo based on the ChatGPT API button $(document).on('click.metainfo', '#adminForm button.jmap-chatgpt-metagenerator', function(jqEvent) { jqEvent.preventDefault(); jqEvent.stopPropagation(); // Retrive information to save var metadataType = ''; var parentTD = $(this).parents('td'); var textareaIdentifier = $('textarea', parentTD); if($(textareaIdentifier).attr('data-titleidentifier')) { var rowIdentifier = $(textareaIdentifier).data('titleidentifier'); metadataType = 'title'; } else if($(textareaIdentifier).attr('data-descidentifier')) { var rowIdentifier = $(textareaIdentifier).data('descidentifier'); metadataType = 'description'; } var linkIdentifier = $('a[data-linkidentifier=' + rowIdentifier + ']').attr('href'); var sitemapLanguage = $('#adminForm input[name=sitemaplanguage]').val(); // Now build the object to send to server endpoint var dataObject = { linkurl : linkIdentifier, type : metadataType, sitemaplang : sitemapLanguage }; // Now save to server side generateChatGPTMeta(dataObject, textareaIdentifier); return false; }); // Bind an event handler for textarea writing, used to count characters and lock/unlock disabled buttons $('table.adminlist tbody textarea, table.adminlist tbody input').on('keyup.metainfo', function(jqEvent) { var parentRow = $(this).parents('tr'); // Update notify button status callback rowButtonStatus(parentRow); }); $('table.adminlist tbody input[type=text]').on('change.metainfo input.metainfo propertychange.metainfo', function(jqEvent) { var parentRow = $(this).parents('tr'); // Update notify button status callback rowButtonStatus(parentRow); }); // Required for Joomla 3.5+ $('table.adminlist tbody button.button-clear, table.adminlist tbody a.button-clear').on('click.metainfo', {context:this}, function(jqEvent) { var parentRow = $(this).parents('tr'); var indentifier = $('td.link_loc a', parentRow).data('linkidentifier'); // Update notify button status callback setTimeout(function(context){ context.refreshRowStatus(parentRow, indentifier); }, 1, jqEvent.data.context) }); // Required for Joomla 3.7+ in order to clear the modal-body and avoid multiple iframes append $('*[id*=imageModal_jform_media_identifier]').on('hide.bs.modal', function(){ $('div.modal-body', this).empty(); }); $('table.adminlist tbody select.robots_directive').on('change.metainfo', function(jqEvent) { var parentRow = $(this).parents('tr'); // Update notify button status callback rowButtonStatus(parentRow); }); // Live event binding only once on initialize, avoid repeated // handlers and executed callbacks if (initialize) { // Live event binding for close button AKA stop process $(document).on('click.metainfo', 'label.closeprecaching', function(jqEvent) { $('#metainfo_process').modal('hide'); }); } // Attach save all event listener $('#toolbar-save button').on('click', function(jqEvent){ jqEvent.preventDefault(); // Start processing $('button[data-action=savemeta].jmap_modified:not([disabled])').trigger('click.metainfo'); // When all promises are resolved start the async duplicated title/desc count $.when.apply($, savePromisesCollection).then(function() { showMessages(COM_JMAP_ALL_METAINFO_SAVED, 'success'); }); return false; }); // Attach auto populate event listener $('#toolbar-database button').on('click', function(jqEvent){ jqEvent.preventDefault(); // Start processing autoPopulateMetainfo(); return false; }); // Facebook debugger link open $(document).on('click', 'span.field-media-preview', function(jqEvent){ var nextInputValue = $(this).nextAll('input.field-media-input').val(); if(nextInputValue) { var rowLinkIdentifier = $('td.link_loc a[data-role=link]', $(this).parents('tr')).attr('href'); window.open('https://developers.facebook.com/tools/debug/?q=' + encodeURIComponent(rowLinkIdentifier) , '_blank'); } }); // Bind popovers to the media img field bindMediaPopovers('span.field-media-preview'); $('input.mediaimagefield').on('change', function(jqEvent){ bindMediaPopovers('span.field-media-preview'); }); }; /** * Show progress dialog bar with informations about the ongoing started * process * * @access private * @return Void */ var showProgress = function(isNew, percentage, type, status, classColor) { // No progress process injected if(isNew) { // Show progress var progressBar = '<div class="progress progress-' + type + ' active">' + '<div id="progress_bar" class="progress-bar" role="progressbar" aria-valuenow="' + percentage + '" aria-valuemin="0" aria-valuemax="100">' + '<span class="sr-only"></span>' + '</div>' + '</div>'; // Build modal dialog var modalDialog = '<div class="modal fade" id="metainfo_process" tabindex="-1" role="dialog" aria-labelledby="progressModal" aria-hidden="true">' + '<div class="modal-dialog">' + '<div class="modal-content">' + '<div class="modal-header">' + '<h4 class="modal-title">' + COM_JMAP_METAINFO_TITLE + '</h4>' + '<label class="closeprecaching glyphicon glyphicon-remove-circle"></label>' + '<p class="modal-subtitle">' + COM_JMAP_METAINFO_PROCESS_RUNNING + '</p>' + '</div>' + '<div class="modal-body">' + '<p>' + progressBar + '</p>' + '<p id="progress_info">' + status + '</p>' + '</div>' + '<div class="modal-footer">' + '</div>' + '</div><!-- /.modal-content -->' + '</div><!-- /.modal-dialog -->' + '</div>'; // Inject elements into content body $('body').append(modalDialog); // Setup modal var modalOptions = { backdrop:'static' }; $('#metainfo_process').modal(modalOptions); // Async event progress showed and styling $('#metainfo_process').on('shown.bs.modal', function(event) { $('#metainfo_process div.modal-body').css({'width':'90%', 'margin':'auto'}); $('#progress_bar').css({'width':percentage + '%'}); // Start AJAX GET request for sitemap generation in the cache folder startSitemapCaching(targetSitemapLink); }); // Remove backdrop after removing DOM modal $('#metainfo_process').on('hidden.bs.modal',function(jqEvent){ $('.modal-backdrop').remove(); $(this).remove(); // Redirect to MVC core cpanel, discard metainfo process window.location.href = 'index.php?option=com_jmap&task=cpanel.display' }); } else { // Refresh only status, progress and text $('#progress_bar').addClass(classColor) .css({'width':percentage + '%'}); $('#progress_bar').parent().removeClass('progress-normal progress-striped') .addClass('progress-' + type); $('#progress_info').html(status); // An error has been detected, so auto close process and progress bar if(classColor == 'progress-bar-danger') { setTimeout(function(){ $('#metainfo_process').modal('hide'); }, 3500); } } } /** * The first operation is get informations about published data sources * and start cycle over all the records using promises and recursion * * @access private * @param String targetSitemapLink * @return Void */ var startSitemapCaching = function(targetSitemapLink) { // No ajax request if no control panel generation in 2 steps if(!targetSitemapLink) { return; } // Request JSON2JSON var dataSourcePromise = $.Deferred(function(defer) { $.ajax({ type : "GET", url : targetSitemapLink, dataType : 'json', context : this, data: {'metainfojsclient' : true} }).done(function(data, textStatus, jqXHR) { if(!data.result) { // Error found defer.reject(COM_JMAP_METAINFO_ERROR_STORING_FILE, textStatus); return false; } // Check response all went well if(data.result) { defer.resolve(); } }).fail(function(jqXHR, textStatus, errorThrown) { // Error found var genericStatus = textStatus[0].toUpperCase() + textStatus.slice(1); defer.reject('-' + genericStatus + '- ' + errorThrown); }); }).promise(); dataSourcePromise.then(function() { // Update process status, we started showProgress(false, 100, 'striped', COM_JMAP_METAINFO_GENERATION_COMPLETE, 'progress-normal'); // Parse sitemap parameters var sitemapParams = parseURL(targetSitemapLink).params; var sitemapLang = sitemapParams.lang ? '&sitemaplang=' + sitemapParams.lang : ''; var sitemapDataset = sitemapParams.dataset ? '&sitemapdataset=' + sitemapParams.dataset : ''; var sitemapMenuID = sitemapParams.Itemid ? '&sitemapitemid=' + sitemapParams.Itemid : ''; // Redirect to MVC core window.location.href = 'index.php?option=com_jmap&task=metainfo.display&metainfojsclient=1' + sitemapLang + sitemapDataset + sitemapMenuID; }, function(errorText, error) { // Do stuff and exit showProgress(false, 100, 'normal', errorText, 'progress-bar-danger'); }); }; /** * Manage the data saving and the status change for each sitemap record * in the model database table * * @access private * @param String action * @param String dataObject * @param Int rowIdentifier * @return Void */ var saveDataStatus = function(action, dataObject, rowIdentifier) { // Object to send to server var ajaxparams = { idtask : action, param: dataObject }; // Unique param 'data' var uniqueParam = JSON.stringify(ajaxparams); // Request JSON2JSON var metainfoPromise = $.Deferred(function(defer) { $.ajax({ type : "POST", url: "../administrator/index.php?option=com_jmap&task=ajaxserver.display&format=json", dataType : 'json', context : this, data : { data : uniqueParam } }).done(function(data, textStatus, jqXHR) { if(!data.result) { // Error found defer.reject(data.exception_message, textStatus); return false; } // Check response all went well if(data.result) { var userMessage = data.exception_message || COM_JMAP_METAINFO_SAVED; defer.resolve(userMessage, data); } }).fail(function(jqXHR, textStatus, errorThrown) { // Error found var genericStatus = textStatus[0].toUpperCase() + textStatus.slice(1); defer.reject('-' + genericStatus + '- ' + errorThrown); }); }).promise(); metainfoPromise.then(function(message, dataResponse) { // Update process status, we started if(action == 'stateMeta' && dataResponse.result && dataResponse.exception_message) { } else { showMessages(message, 'success'); } }, function(errorText, error) { // Do stuff and exit showMessages(errorText, 'error'); }); // Assign the promise to the collection if(rowIdentifier) { savePromisesCollection[rowIdentifier] = metainfoPromise; } }; /** * Manage the data saving and the status change for each sitemap record * in the model database table * * @access private * @param String dataObject * @param HTMLElement targetTextArea * @return Void */ var generateChatGPTMeta = function(dataObject, targetTextArea) { // Object to send to server var ajaxparams = { idtask : 'generateChatGPTMeta', param: dataObject, DIModels: [ { 'modelside' : 1, 'modelname' : 'Aigenerator' }, { 'modelside' : 1, 'modelname' : 'Metainfo' } ] }; // Store the row and column context var parentColumn = $(targetTextArea).parents('td'); var parentRow = $(targetTextArea).parents('tr'); // Set the working icon $('button.jmap-chatgpt-metagenerator img.jmap-chatgpt-icon', parentColumn).attr('src', jmap_baseURI + 'administrator/components/com_jmap/images/loading.gif'); // Unique param 'data' var uniqueParam = JSON.stringify(ajaxparams); // Request JSON2JSON var metainfoPromise = $.Deferred(function(defer) { $.ajax({ type : "POST", url: "../administrator/index.php?option=com_jmap&task=ajaxserver.display&format=json", dataType : 'json', context : this, data : { data : uniqueParam } }).done(function(data, textStatus, jqXHR) { if(!data.result) { // Error found defer.reject(data.exception_message, textStatus); return false; } // Check response all went well if(data.result) { var resultMessage = data.exception_message || COM_JMAP_AIGENERATOR_METAINFO_GENERATED; defer.resolve(resultMessage, data); } }).fail(function(jqXHR, textStatus, errorThrown) { // Error found var genericStatus = textStatus[0].toUpperCase() + textStatus.slice(1); defer.reject('-' + genericStatus + '- ' + errorThrown); }); }).promise(); metainfoPromise.then(function(message, dataResponse) { // Update process status, we started if(dataResponse.result && dataResponse.exception_message) { } else { showMessages(message, 'success'); // Populate the just generated metadata in the matching field $(targetTextArea).text(dataResponse.generated); $(targetTextArea).val(dataResponse.generated); // Update refresh status rowButtonStatus(parentRow); $(targetTextArea).trigger('keyup.metainfo'); } }, function(errorText, error) { // Do stuff and exit showMessages(errorText, 'error'); }).always(function(){ $('button.jmap-chatgpt-metagenerator img.jmap-chatgpt-icon', parentColumn).attr('src', jmap_baseURI + 'administrator/components/com_jmap/images/chatgpt-logo.svg'); }); }; /** * Evaluate and keep synced the enabled buttons status based on the current row values * * @access private * @param specificRow * @return Void */ var rowButtonStatus = function(specificRow) { // Search for each row if at least one of the 3 values is specified and only in that case enable buttons var finalSelector = specificRow || 'table.adminlist tbody tr'; $(finalSelector).each(function(index, tableRow){ var titleValue = $('textarea.metatitle', tableRow).val(); var descValue = $('textarea.metadesc', tableRow).val(); var imageValue = $('input.mediaimagefield', tableRow).val(); var robotsValue = $('select.robots_directive', tableRow).val(); // If none of the value are available disable buttons if(!titleValue && !descValue && !imageValue && !robotsValue) { $('button:not(.button-select):not(.close):not(.jmap-chatgpt-metagenerator), fieldset.radio[data-action=statemeta] label', tableRow).attr('disabled', true); $('fieldset.radio[data-action=statemeta] label', tableRow).addClass('jmap_inactive'); if(specificRow) { $('button[data-action=savemeta]', tableRow).removeClass('jmap_modified'); } } else { $('button, fieldset.radio[data-action=statemeta] label', tableRow).removeAttr('disabled'); $('fieldset.radio[data-action=statemeta] label', tableRow).removeClass('jmap_inactive'); if(specificRow) { $('button[data-action=savemeta]', tableRow).addClass('jmap_modified'); } } }); }; /** * Extend the jQuery prototype with a plugin to count and validate * the length of the textarea characters */ var addTextareaLengthvalidation = function() { // jQuery prototype $.fn.textWidth = function(text, font) { if (!$.fn.textWidth.fakeEl) { $.fn.textWidth.fakeEl = $('<span class="jmapmetainfo_fake_element">').appendTo(document.body); } $.fn.textWidth.fakeEl.text(text).css('font', font); return parseInt($.fn.textWidth.fakeEl.width()); }; $.fn.jmapCharacterCount = function charCount(options) { var defaults = { limit : 100 }; var options = $.extend({}, defaults, options); if (this.length) { return $(this).each(function charCountEachElement() { var $this = $(this); var addElements = function() { $this.next('img.hasTooltip').remove(); $this.container = $('<span/>'); $this.counterCharacter = $('<span/>').attr('title', COM_JMAP_CHARACTERS).addClass('label labelmetainfo').addClass('label-primary').html( '<span class="jmapmetainfo_chars_count glyphicon glyphicon-align-left"></span><span class="jmap_metainfo_counter">' + 0 + '</span>'); $this.counterPxDesktop = $('<span/>').attr('title', COM_JMAP_PIXEL_DESKTOP).addClass('label labelmetainfo').addClass('label-primary').html( '<span class="jmapmetainfo_pixel_count glyphicon glyphicon-blackboard"></span><span class="jmap_metainfo_counter_pixel">' + 0 + 'px</span>'); $this.counterPxMobile = $('<span/>').attr('title', COM_JMAP_PIXEL_MOBILE).addClass('label labelmetainfo').addClass('label-primary').html( '<span class="jmapmetainfo_pixel_count glyphicon glyphicon-phone"></span><span class="jmap_metainfo_counter_pixel">' + 0 + 'px</span>'); $this.after($this.container); $this.container.append($this.counterCharacter); $this.container.append($this.counterPxDesktop); $this.container.append($this.counterPxMobile); // ChatGPT generation to enable based by settings if(jmap_chatgptGeneration) { if($this.hasClass('metatitle')) { var chatGPTTooltip = 'Click to generate the meta title with ChatGPT'; } else { var chatGPTTooltip = 'Click to generate the meta description with ChatGPT'; } $this.chatgptGenerationButton = $('<button class="jmap-chatgpt-metagenerator" title="' + chatGPTTooltip + '"><img class="jmap-chatgpt-icon" src="' + jmap_baseURI + 'administrator/components/com_jmap/images/chatgpt-logo.svg" alt="ChatGPT"></button>'); $this.container.append($this.chatgptGenerationButton); } }; $this.update = function() { var length = $this.val().length; if($this.hasClass('metatitle')) { var desktopLength = $.fn.textWidth($this.val(), titleFontDesktop); var mobileLength = $.fn.textWidth($this.val(), titleFontMobile); } else if($this.hasClass('metadesc')) { var desktopLength = $.fn.textWidth($this.val(), descriptionFontDesktop); var mobileLength = $.fn.textWidth($this.val(), descriptionFontMobile); } $this.counterCharacter.html('<span title="' + COM_JMAP_CHARACTERS + '" class="jmapmetainfo_chars_count glyphicon glyphicon-align-left"></span><span class="jmap_metainfo_counter">' + length + '</span>'); $this.counterPxDesktop.html('<span title="' + COM_JMAP_PIXEL_DESKTOP + '" class="jmapmetainfo_pixel_count glyphicon glyphicon-blackboard"></span><span class="jmap_metainfo_counter_pixel">' + desktopLength + 'px</span>'); $this.counterPxMobile.html('<span title="' + COM_JMAP_PIXEL_MOBILE + '" class="jmapmetainfo_pixel_count glyphicon glyphicon-phone"></span><span class="jmap_metainfo_counter_pixel">' + mobileLength + 'px</span>'); // Warning class for the characters count if (options.limit < length) { $this.counterCharacter.removeClass('label-primary'); $this.counterCharacter.addClass('label-danger'); } else { $this.counterCharacter.removeClass('label-danger'); $this.counterCharacter.addClass('label-primary'); } // Warning class for title pixel count if($this.hasClass('metatitle')) { if (maxLengthTitleDesktop < desktopLength) { $this.counterPxDesktop.removeClass('label-primary'); $this.counterPxDesktop.addClass('label-danger'); } else { $this.counterPxDesktop.removeClass('label-danger'); $this.counterPxDesktop.addClass('label-primary'); } if (maxLengthTitleMobile < mobileLength) { $this.counterPxMobile.removeClass('label-primary'); $this.counterPxMobile.addClass('label-danger'); } else { $this.counterPxMobile.removeClass('label-danger'); $this.counterPxMobile.addClass('label-primary'); } } // Warning class for description pixel count if($this.hasClass('metadesc')) { if (maxLengthDescriptionDesktop < desktopLength) { $this.counterPxDesktop.removeClass('label-primary'); $this.counterPxDesktop.addClass('label-danger'); } else { $this.counterPxDesktop.removeClass('label-danger'); $this.counterPxDesktop.addClass('label-primary'); } if (maxLengthDescriptionMobile < mobileLength) { $this.counterPxMobile.removeClass('label-primary'); $this.counterPxMobile.addClass('label-danger'); } else { $this.counterPxMobile.removeClass('label-danger'); $this.counterPxMobile.addClass('label-primary'); } } }; $this.on('keyup.metainfo', function(event) { $this.update(); }); addElements(); $this.update(); }); } }; }; /** * Process the asyncronous analysis of links * Auto populates the metainfo links records providing the auto click on the save button * * @access private * @return Void */ var autoPopulateMetainfo = function() { // Retrieve all the links to analyze on page var linksToAnalyze = $('a[data-role=link]'); // No ajax request if no links to analyze if(!linksToAnalyze.length) { return; } $.each(linksToAnalyze, function(index, link){ var targetCrawledLink = $('a[data-role="link"]').get(index); var targetTitle = $('textarea[data-bind="{title}"]').get(index); var targetDesc = $('textarea[data-bind="{desc}"]').get(index); var targetRobots = $('select[data-bind="{robots}"]').get(index); var targetSocialImage = $('input.field-media-input.mediaimagefield').get(index); // Preappend a loading progress waiter to each processed link $(targetCrawledLink).after('<img class="metainfo_loader" width="16px" height="16px" src="' + jmap_baseURI + 'administrator/components/com_jmap/images/loading.gif' + '"/>'); promisesCollection[index] = $.Deferred(function(defer) { setTimeout(function(){ $.ajax({ type : "GET", url : $(link).attr('href'), }).done(function(data, textStatus, jqXHR) { // Check response HTTP status code defer.resolve(data, jqXHR.status); }).fail(function(jqXHR, textStatus, errorThrown) { // Error found defer.resolve(null, jqXHR.status); }); }, index * jmap_crawlerDelay); }).promise(); promisesCollection[index].then(function(responseData, status) { // Always remove the waiter $(targetCrawledLink).next('img.metainfo_loader').remove(); // STEP 1 - If the status validation is not 200 OK simply skip to next link promise if(status != 200) { return; } // Set init status for this row iteration var titlePopulated = false; var descPopulated = false; var robotsPopulated = false; var socialImagePopulated = false; // Set the parsed wrapped set var responseDataWrappedSet = $(responseData.trim()); // STEP 2 - Title retrieval and reporting var title = responseDataWrappedSet.filter('title').text().trim(); // Remove the site name suffix/prefix part in the title if any if(jmap_siteNamePageTitles > 0) { switch (jmap_siteNamePageTitles) { // Prepended before prefix case 1: title = title.replace(jmap_siteName + ' - ', ''); break; // Appended after suffix case 2: title = title.replace(' - ' + jmap_siteName, ''); break; } } // Manage title validity, preserve existing values var existingTargetTitle = $(targetTitle).text(); if(title && !existingTargetTitle && jmap_metainfoAutoGenerateMetatitle != 2) { $(targetTitle).text( title ).val( title ); titlePopulated = true; } // Evaluate the meta title excerpt auto-generation if(!titlePopulated && !existingTargetTitle && jmap_metainfoAutoGenerateMetatitle) { var autoGeneratedTitleText = ''; var titleSource = $(jmap_metainfoAutoGenerateMetatitleCssSelector, $.parseHTML(responseData)).text().trim().replace(/\s\s+/g, ' '); var titleSourceLength = titleSource.length; if(titleSourceLength > 0) { if(titleSourceLength > jmap_metainfoAutoGenerateMetatitleMaxLength) { autoGeneratedTitleText = titleSource.substr(0, jmap_metainfoAutoGenerateMetatitleMaxLength) + '...'; } else { autoGeneratedTitleText = titleSource; } $(targetTitle).text( autoGeneratedTitleText ).val( autoGeneratedTitleText ); titlePopulated = true; } } // STEP 3 - Description retrieval and reporting var description = responseDataWrappedSet.filter('meta[name=description]').attr('content') || ''; description = description.trim(); // Manage description validity, preserve existing values var existingTargetDesc = $(targetDesc).text(); if(description && !existingTargetDesc && jmap_metainfoAutoGenerateMetadescription != 2) { $(targetDesc).text( description ).val( description ); descPopulated = true; } // Evaluate the meta description excerpt auto-generation if(!descPopulated && !existingTargetDesc && jmap_metainfoAutoGenerateMetadescription) { var autoGeneratedDescriptionText = ''; var descriptionSource = $(jmap_metainfoAutoGenerateMetadescriptionCssSelector, $.parseHTML(responseData)).text().trim().replace(/\s\s+/g, ' '); var descriptionSourceLength = descriptionSource.length; if(descriptionSourceLength > 0) { if(descriptionSourceLength > jmap_metainfoAutoGenerateMetadescriptionMaxLength) { autoGeneratedDescriptionText = descriptionSource.substr(0, jmap_metainfoAutoGenerateMetadescriptionMaxLength) + '...'; } else { autoGeneratedDescriptionText = descriptionSource; } $(targetDesc).text( autoGeneratedDescriptionText ).val( autoGeneratedDescriptionText ); descPopulated = true; } } // STEP 4 - Robots directive retrieval and selecting var robots = responseDataWrappedSet.filter('meta[name=robots]').attr('content') || ''; robots = robots.trim(); // Manage description validity, preserve existing values if(robots && !$(targetRobots).val()) { $(targetRobots).val( robots ); robotsPopulated = true; } // STEP 5 - Social image retrieval and selecting if(jmap_metainfoAutopopulateSocialimageSelector) { var socialImage = responseDataWrappedSet.find(jmap_metainfoAutopopulateSocialimageSelector).attr('src') || responseDataWrappedSet.find(jmap_metainfoAutopopulateSocialimageSelector).attr('data-src') || ''; socialImage = socialImage.trim().replace(/^\//, ""); // Manage description validity, preserve existing values if(socialImage && !$(targetSocialImage).val()) { // Check for sub folder overlap var baseChunksLastChunk = jmap_baseURI.replace(/\/$/, "").split('/').pop(); var imageChunksFirstChunk = socialImage.split('/')[0]; if(baseChunksLastChunk == imageChunksFirstChunk) { socialImage = socialImage.replace(baseChunksLastChunk + '/', ''); } $(targetSocialImage).val( socialImage ).attr('value', socialImage); // Refresh the image popover var imgPreview = new Image(200, 200); // Regex pattern for checking absolute URL var pattern = /^http(s)?:\/\//i; // Check if pattern is there in the string or not with .test() method if (pattern.test(socialImage)) { imgPreview.src = socialImage; } else { imgPreview.src = jmap_baseURI + socialImage; } var containerPreview = $(targetSocialImage).prev('span.field-media-preview'); try { containerPreview.popover('destroy'); } catch(err) {} containerPreview.popover({content: imgPreview}); socialImagePopulated = true; } } // Now trigger the change event for this row if(titlePopulated || descPopulated || robotsPopulated || socialImagePopulated) { $(targetTitle).trigger('keyup.metainfo'); $(targetDesc).trigger('keyup.metainfo'); // Finally trigger the save data button to persist var targetSaveBtn = $('button[data-action=savemeta]').get(index); $(targetSaveBtn).trigger('click.metainfo'); } }); }); }; /** * Request a refresh of the row status * * @access public * @param Object parentRow * @param Integer identifier * @return Void */ this.refreshRowStatus = function(parentRow, identifier) { rowButtonStatus(parentRow); // Check if it's a deletion meta image after a button click in the media widget var titleValue = $('textarea.metatitle', parentRow).val(); var descValue = $('textarea.metadesc', parentRow).val(); var imageValue = $('input.mediaimagefield', parentRow).val(); var robotsValue = $('select.robots_directive', parentRow).val(); // If none of the values are available AKA empty record delete on server if(!titleValue && !descValue && !imageValue && !robotsValue) { // Retrive information to save var linkIdentifier = $('a[data-linkidentifier=' + identifier + ']').attr('href'); // Now build the object to send to server endpoint var dataObject = { linkurl : linkIdentifier }; // Now save to server side saveDataStatus('deleteMeta', dataObject); } }; /** * Request a refresh of the row status * * @access public * @return Void */ this.startMetaCount = function() { $('table.adminlist tbody textarea.metatitle').jmapCharacterCount({ limit: 70 }); $('table.adminlist tbody textarea.metadesc').jmapCharacterCount({ limit: 160 }); // Enable Bootstrap tooltips $('span.labelmetainfo').tooltip({trigger:'hover', placement:'top', html : 1}); $('button.jmap-chatgpt-metagenerator').tooltip({trigger:'hover', placement:'top', html : 1}); }; /** * Function dummy constructor * * @access private * @param String * contextSelector * @method <<IIFE>> * @return Void */ (function __construct() { // Search for each row if at least one of the 3 values is specified and only in that case enable buttons rowButtonStatus(); // Extend jQuery with plugins addTextareaLengthvalidation(); // Manage the async font loading for the update controls if(typeof(WebFont) !== 'undefined') { WebFont.load({ google: { families: ['Roboto:400'] } }); } // Fix for Joomla 3.5 modals $('td.metaimage a.button-select').on('click', function(jqEvent) { $('button[data-dismiss=modal]').removeAttr('disabled'); }) $('td.metaimage input.field-media-input.mediaimagefield').removeAttr('readonly'); $('#toolbar-database button, #toolbar-save button').removeAttr('onclick'); // Add UI events addListeners.call(this, true); }).call(this); } // On DOM Ready $(function() { window.JMapMetainfo = new Metainfo(); }); })(jQuery);
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Генерация страницы: 0.1 |
proxy
|
phpinfo
|
Настройка