Incorrect values for Navigation Timing API in IE11 for pages with iFrames - internet-explorer-11

While Calculating the server response time by subtracting the requestStart time from responseStart time of the Navigation Timing API, the difference is close to 0 many times on IE11 and this doesn't match with the data from the server side. This happens on pages with iframes is this a known issue or is there a workaround for this?
window.performance.timing.responseStart-window.performance.timing.requestStart
on Chrome the results are closer to server side times but not on IE11

Please make sure the request page contains enough elements and spend time to load.
Then, try to clear the cache and refresh the page (could also use Ctrl+F5 or Enable the F12 developer tools "Always refresh from server" option).
You could refer to the following code:
<body>
Go back to the article
<h1>Navigation Timing API</h1>
<span id="nt-unsupported" class="hidden">API not supported</span>
<h2>Timing info</h2>
<ul id="timing-list"></ul>
<h2>Navigation info</h2>
<ul id="navigation-list"></ul>
<small class="author">
Demo created by Aurelio De Rosa
(#AurelioDeRosa).<br />
This demo is part of the HTML5 API demos repository.
</small>
<img src="Images/Image2.jpg" />
<img src="Images/Image1.jpg" />
<img src="Images/Image3.jpg" />
<img src="Images/Image2.jpg" />
<img src="Images/Image1.jpg" />
<img src="Images/Image3.jpg" />
<script>
if (!('performance' in window) ||
!('timing' in window.performance) ||
!('navigation' in window.performance)
) {
document.getElementById('nt-unsupported').className = '';
} else {
window.addEventListener('load', function () {
var list = '';
var timings = window.performance.timing;
for (var timing in timings) {
list += '<li>' + timing + ': <span class="value">' + timings[timing] + '</span></li>';
}
list += '<li>window.performance.timing.responseStart - window.performance.timing.requestStart : <span>' + (window.performance.timing.responseStart - window.performance.timing.requestStart) + '</span></li>';
document.getElementById('timing-list').innerHTML = list;
list = '';
list += '<li>redirectCount: <span class="value">' + window.performance.navigation['redirectCount'] + '</span></li>';
list += '<li>type: <span class="value">' + window.performance.navigation['type'] + '</span></li>';
document.getElementById('navigation-list').innerHTML = list;
});
}
</script>
</body>
the result as below:

Related

Render html code in Vue.Js without using v-html

I am facing a strange problem.
I use VueTableDynamic as a table library (https://github.com/TheoXiong/vue-table-dynamic)
The whole implementation is correct but there is a small problem... I have certain columns that I want to render with html (for example I want to put a download icon with an href)
this.invoices_params.data.push([
invoice.invoice_number,
invoice.user.company_name ? invoice.user.company_name : invoice.user.first_name + ' ' + invoice.user.last_name,
invoice.total,
(119 / 100) * invoice.total,
invoice.media.length > 0 ?
`<a href=${invoice.media[0].original_url}>Download invoice</a>` :
'No invoice',
moment(invoice.created_at).format('DD-MM-YYYY H:m:s'),
]);
<div class="col-lg" v-if="checkbox_invoices">
{{ trans.invoices.title }}
<vue-table-dynamic :params="invoices_params"></vue-table-dynamic>
</div>
But I can't render that html code and I don't think I can use v-html either
Is there just a way to put that icon there?
I tried to put automatic html code but in vain.
The library allows you to customize the content of a cell using slots: https://github.com/TheoXiong/vue-table-dynamic#slot
Example:
<template>
<vue-table-dynamic :params="params">
<template v-slot:column-5="{ props }">
<a v-if="props.cellData" href=${props.cellData}>Download invoice</a>
<span v-else>No invoice</span>
</template>
</vue-table-dynamic>
</template>
<script>
[...]
this.invoices_params.data.push([
invoice.invoice_number,
invoice.user.company_name ? invoice.user.company_name : invoice.user.first_name + ' ' + invoice.user.last_name,
invoice.total,
(119 / 100) * invoice.total,
invoice.media.length > 0 ? invoice.media[0].original_url : null,
moment(invoice.created_at).format('DD-MM-YYYY H:m:s'),
]);
</script>

VueJS unexpectedly runs a function

Hello guys specially VueJS devs theres something weird happened. Ill explain it one by one
Full video:
https://drive.google.com/file/d/1G2ksQsMQ1LB868dg29f8mm4NR_x5GycF/view?fbclid=IwAR1YmYbo3J6jHrY6PHd8E_lxA47VJSXV6G3132_uF6Or3bXv7MbnQbRvKaU
I use datatable and then i use this getDefaultPrice() to manipulate the price because the format of my price is like this ("65;75") to return the first value to PHP 65.00
then once i click the add to cart button please see image for codes the getDefaultPrice() also executed.
and I received an error "price.split is not a function" I tried to console.log the function and it really runs it without calling it in my add_to_cart();
<td>
<p>{{getDefaultPrice(product.price)}}</p>
</td>
<td>
<button
class="btn main_bg_color add_to_cart_btn" data-toggle="modal" data-target="#productModal"
#click="add_to_cart(product)"
>
<i class="fa fa-shopping-cart"></i> Add to cart
</button>
</td>
add_to_cart(product) {
this.modal_data = [];
this.modal_data.push(product)
this.modal_data[0].variation = this.modal_data[0].variation.split(';');
this.modal_data[0].price = this.modal_data[0].price.split(';');
this.modal_data[0].drinks_price = this.modal_data[0].drinks_price.split(';');
this.modal_data[0].drinks = this.modal_data[0].drinks.split(';');
},
getDefaultPrice(price) {
console.log("test")
var price_arr = price.split(";");
var default_price = parseFloat(price_arr[0]);
return "PHP " + default_price.toFixed(2);
},

v-html with conditional rendered

I'm learning Vue.js and I really love it, but I'm currently facing a problem.
I have this code in my template:
<button type="button" class="btn btn-warning ml-auto" v-if="steps.length - 1 == currentStep" #click="submitProject" v-html="paymentAmount">{{model.projectSelectedOptions.length < 1 ? 'Publish without option (free)' : paymentAmount }}</button>
And the paymentAmount computed:
paymentAmount() {
var amount = 0;
this.model.projectSelectedOptions.forEach(function(option) {
if (option == 1) {
option = 19.99
} else if (option == 2) {
option = 9.99
} else {
option = 7.99
}
amount += option;
});
return 'Next : payment (' + amount.toFixed(2) + ' € <span class="price-ht">HT</span>)';
}
My problem is that if I put v-html="paymentAmount" in my button, I never see "Publish without option (free)", just "Next : payment (0 € HT)".
If I remove v-html attribute, I can see "Publish without option (free)" but when I have selected some options, Vue.js render "Next : payment (0 € <span class="price-ht">HT</span>)" (so with raw span).
How should I do it?
EDIT:
For the moment, I added a button with a different v-if condition, but it would be cool if I can do it in one line of code, I don't like the duplicate 😅.
How about putting all your logic inside of your computed property?
HTML part:
<button type="button" class="btn btn-warning ml-auto" v-if="steps.length - 1 == currentStep" #click="submitProject" v-html="paymentAmount"></button>
Vue part:
paymentAmount() {
if(this.model.projectSelectedOptions.length < 1)
{
return 'Publish without option (free)';
}
else
{
var amount = 0;
this.model.projectSelectedOptions.forEach(function(option) {
if (option == 1) {
option = 19.99
} else if (option == 2) {
option = 9.99
} else {
option = 7.99
}
amount += option;
});
return 'Next : payment (' + amount.toFixed(2) + ' € <span class="price-ht">HT</span>)';
}
}
You might use a conditional span as button content:
<button
type="button"
class="btn btn-warning ml-auto"
v-if="steps.length - 1 == currentStep"
#click="submitProject">
<span v-if="model.projectSelectedOptions.length < 1">Publish without option (free)</span>
<span v-else v-html="paymentAmount"></span>
</button>

Product autocomplete input on module (Prestashop)

I'm developing a prestashop module that has to make lists of existing products.
For the configuration panel of the module, using renderForm() and getContent(), I'm trying to replicate the "accesories" capability, where you start writing some info of a product on an input, and it shows the products that are a match. When selecting that product, it gets added on a list. Like this:
This a screenshot of Catalog / Products / Associations tab.
I'm trying with PS 1.6.0.14 and PS1.6.1.0RC3. How would I replicate this functionality to get lists of products on a module configuration panel?
I tried looking here Prestashop AdminProductsController.php but I don't really understand where half of that info is coming from.
There is an autocomplete plugin in prestashop you got to use that for this. Its in js->jquery->plugins you got to add this plugin into your module to make it work.
I think that to achieve that functionality, the renderForm() function won't be enough since you have to bind some javascript and some custom html.
The process of writing a fully functional module is a bit long but by taking the accessories functionality as a starting point it wont be so hard and you will always have a reference on "how-to-do-it".
I would go with this:
1) first create your
getContent()
function to be able to show the custom template and the product associated by your module so we will have something along:
public function getContent(){
//post process part to save the associations
if(Tools::isSubmit('saveMyAssociations'){
... //we will see it later
}
$my_associations = MyModule::getAssociationsLight($this->context->language->id,Tools::getValue('id_product')); //function that will retrieve the array of all the product associated on my module table.
$this->context->smarty->assign(array(
'my_associations' => $my_associations,
'product_id' => (int)Tools::getValue('id_product')
));
return $this->display(__FILE__, 'views/templates/admin/admintemplate.tpl'); //custome template to create the autocomplete
}
//our little function to get the already saved list, for each product we will retrieve id, name and reference with a join on the product/product_lang tables.
public static function getAssociationsLight($id_lang, $id_product, Context $context = null)
{
if (!$context)
$context = Context::getContext();
$sql = 'SELECT p.`id_product`, p.`reference`, pl.`name`
FROM `'._DB_PREFIX_.'my_associations`
LEFT JOIN `'._DB_PREFIX_.'product` p ON (p.`id_product`= `id_product_2`)
'.Shop::addSqlAssociation('product', 'p').'
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (
p.`id_product` = pl.`id_product`
AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').'
)
WHERE `id_product_1` = '.(int)$id_product;
return Db::getInstance()->executeS($sql);
}
2) create a template that will be able to show the automplete and the list.
Here we will loop trough the saved associations to create our autocomplete list, and we will do it with some hidden field to keep track of the ids/name and also a visible list were we will have a delete button for each row.
<input type="hidden" name="inputMyAssociations" id="inputMyAssociations" value="{foreach from=$my_associations item=accessory}{$accessory.id_product}-{/foreach}" />
<input type="hidden" name="nameMyAssociations" id="nameMyAssociations" value="{foreach from=$my_associations item=accessory}{$accessory.name|escape:'html':'UTF-8'}¤{/foreach}" />
<div id="ajax_choose_product_association">
<div class="input-group">
<input type="text" id="product_autocomplete_input_association" name="product_autocomplete_input_association" />
<span class="input-group-addon"><i class="icon-search"></i></span>
</div>
</div>
<div id="divMyAssociations">
{foreach from=$my_associations item=accessory}
<div class="form-control-static">
<button type="button" class="btn btn-default delAssociation" name="{$accessory.id_product}">
<i class="icon-remove text-danger"></i>
</button>
{$accessory.name|escape:'html':'UTF-8'}{if !empty($accessory.reference)}{$accessory.reference}{/if}
</div>
{/foreach}
</div>
<input type="submit" name="submitMyAssociations" id="submitMyAssociations" value="Send"/>
<input type="hidden" name="productId" id="productId" value="{$product_id|escape:'html'}"/>
3) Now we can add the javascript to bind an autocomplete on the main input and perform all the logic for each action
$(document).ready(function(){
//our function wrapper.
var initMyAssociationsAutocomplete = function (){
//initialize the autocomplete that will point to the default ajax_products_list page (it returns the products by id+name)
$('#product_autocomplete_input_association')
.autocomplete('ajax_products_list.php', {
minChars: 1,
autoFill: true,
max:20,
matchContains: true,
mustMatch:true,
scroll:false,
cacheLength:0,
formatItem: function(item) {
return item[1]+' - '+item[0];
}
}).result(addAssociation);
//as an option we will add a function to exclude a product if it's already in the list
$('#product_autocomplete_input_association').setOptions({
extraParams: {
excludeIds : getAssociationsIds()
}
});
};
//function to exclude a product if it exists in the list
var getAssociationsIds = function()
{
if ($('#inputMyAssociations').val() === undefined)
return '';
return $('#inputMyAssociations').val().replace(/\-/g,',');
}
//function to add a new association, adds it in the hidden input and also as a visible div, with a button to delete the association any time.
var addAssociation = function(event, data, formatted)
{
if (data == null)
return false;
var productId = data[1];
var productName = data[0];
var $divAccessories = $('#divCrossSellers');
var $inputAccessories = $('#inputMyAssociations');
var $nameAccessories = $('#nameMyAssociations');
/* delete product from select + add product line to the div, input_name, input_ids elements */
$divAccessories.html($divAccessories.html() + '<div class="form-control-static"><button type="button" class="delAssociation btn btn-default" name="' + productId + '"><i class="icon-remove text-danger"></i></button> '+ productName +'</div>');
$nameAccessories.val($nameAccessories.val() + productName + '¤');
$inputAccessories.val($inputAccessories.val() + productId + '-');
$('#product_autocomplete_input_association').val('');
$('#product_autocomplete_input_association').setOptions({
extraParams: {excludeIds : getAssociationsIds()}
});
};
//the function to delete an associations, delete it from both the hidden inputs and the visible div list.
var delAssociations = function(id)
{
var div = getE('divMyAssociations');
var input = getE('inputMyAssociations');
var name = getE('nameMyAssociations');
// Cut hidden fields in array
var inputCut = input.value.split('-');
var nameCut = name.value.split('¤');
if (inputCut.length != nameCut.length)
return alert('Bad size');
// Reset all hidden fields
input.value = '';
name.value = '';
div.innerHTML = '';
for (i in inputCut)
{
// If empty, error, next
if (!inputCut[i] || !nameCut[i])
continue ;
// Add to hidden fields no selected products OR add to select field selected product
if (inputCut[i] != id)
{
input.value += inputCut[i] + '-';
name.value += nameCut[i] + '¤';
div.innerHTML += '<div class="form-control-static"><button type="button" class="delAssociation btn btn-default" name="' + inputCut[i] +'"><i class="icon-remove text-danger"></i></button> ' + nameCut[i] + '</div>';
}
else
$('#selectAssociation').append('<option selected="selected" value="' + inputCut[i] + '-' + nameCut[i] + '">' + inputCut[i] + ' - ' + nameCut[i] + '</option>');
}
$('#product_autocomplete_input_association').setOptions({
extraParams: {excludeIds : getAssociationsIds()}
});
};
//finally initialize the function we have written above and create all the binds.
initMyAssociationsAutocomplete();
//live delegation of the deletion button to our delete function, this will allow us to delete also any element added after the dom creation with the ajax autocomplete.
$('#divMyAssociations').delegate('.delAssociation', 'click', function(){
delAssociations($(this).attr('name'));
});
});
4) now you just need to save the associations made by your module autocomplete, and i suggest to perform it by first deleting any association made on a given product and then saving all of them. so you don't have to care about inserting or updating an entry
public function getContent(){
//post process part
if(Tools::isSubmit('saveMyAssociations'){
$product_id = (int)Tools::getValue('productId');
// see the function below, a simple query to delete all the associations on a product
$this->deleteMyAssociations($product_id);
if ($associations = Tools::getValue('inputMyAssociations'))
{
$associations_id = array_unique(explode('-', $associations));
if (count($associations_id))
{
array_pop($associations_id);
//insert all the association we have made.
$this->changeMyAssociations($associations_id, $product_id);
}
}
}
}
protected function deleteMyAssociations($product_id){
return Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'my_associations` WHERE `id_product_1` = '.(int)$product_id);
}
protected function changeMyAssociations($associations_id, $product_id){
foreach ($associations_id as $id_product_2)
Db::getInstance()->insert('my_associations', array(
'id_product_1' => (int)$product_id,
'id_product_2' => (int)$id_product_2
));
}
I hope it can help you to go through all of this.

How to enable the Google Trusted Stores without having Platinum Level in Bigcommerce

I would like to enable the Google Trusted Stores code without having to subscribe to the Platinum Level (I'm on a Gold Level plan). I have successfully set up automated daily Shipping and Cancellation Feeds through ShipWorks. I believe I set up the "Badge" code correctly on the footer.html:
<!-- BEGIN: Google Trusted Stores -->
<script type="text/javascript">
var gts = gts || [];
gts.push(["id", "######"]);
gts.push(["badge_position", "BOTTOM_RIGHT"]);
gts.push(["locale", "en_AU"]);
gts.push(["google_base_offer_id", "%%GLOBAL_ProductId%%"]);
gts.push(["google_base_subaccount_id", "8669332"]);
gts.push(["google_base_country", "AU"]);
gts.push(["google_base_language", "en_AU"]);
(function() {
var gts = document.createElement("script");
gts.type = "text/javascript";
gts.async = true;
gts.src = "https://www.googlecommerce.com/trustedstores/api/js";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(gts, s);
})();
</script>
<!-- END: Google Trusted Stores -->
I have to put the Order Confirmation Module Code on the website. The issue is figuring out the Est. Ship Date and Est. Delivery Date and putting in a "loop" to get the requested data for each item in the order. I have placed the following code on the order.html page:
<!-- start order and merchant information -->
<span id="gts-o-id">%%GLOBAL_OrderId%%</span>
<span id="gts-o-domain">www.****.com.au</span>
<span id="gts-o-email">%%GLOBAL_CurrentCustomerEmail%%</span>
<span id="gts-o-country">%%GLOBAL_ShipCountry%%</span>
<span id="gts-o-currency">%%GLOBAL_CurrencyName%%</span>
<span id="gts-o-total">%%GLOBAL_OrderTotal%%</span>
<span id="gts-o-discounts">%%GLOBAL_CouponDiscount%%</span>
<span id="gts-o-shipping-total">%%GLOBAL_ShippingPrice%%</span>
<span id="gts-o-tax-total">%%GLOBAL_TaxCost%%</span>
<span id="gts-o-est-ship-date">ORDER_EST_SHIP_DATE</span>
<span id="gts-o-est-delivery-date">ORDER_EST_DELIVERY_DATE</span>
<span id="gts-o-has-preorder">N</span>
<span id="gts-o-has-digital">N</span>
<!-- end order and merchant information -->
<!-- start repeated item specific information -->
<!-- item example: this area repeated for each item in the order -->
<span class="gts-item">
<span class="gts-i-name">%%GLOBAL_ProductName%%</span>
<span class="gts-i-price">%%GLOBAL_ProductPrice%%</span>
<span class="gts-i-quantity">%%GLOBAL_ProductQuantity%%</span>
<span class="gts-i-prodsearch-id">%%GLOBAL_ProductId%%</span>
<span class="gts-i-prodsearch-store-id">######</span>
<span class="gts-i-prodsearch-country">AU</span>
<span class="gts-i-prodsearch-language">en_AU</span>
</span>
<!-- end item 1 example -->
<!-- end repeated item specific information -->
</div>
<!-- END Google Trusted Stores Order -->
I have tried with the code for the badge and successfully got approved. as far as the conversion module. I had to do a "Hack" with javascript for the EST ship date and EST delivery date:
<!-- Include the conversion tracking code for all analytics packages -->
<!-- START Google Trusted Stores Order -->
<div id="gts-order" style="display:none;" translate="no">
<!-- start order and merchant information -->
<span id="gts-o-id">%%ORDER_ID%%</span>
<span id="gts-o-domain">www.doubletakeshapewear.com</span>
<span id="gts-o-email">%%ORDER_EMAIL%%</span>
<span id="gts-o-country">%%GLOBAL_ShipCountry%%</span>
<span id="gts-o-currency">%%GLOBAL_CurrencyName%%</span>
<span id="gts-o-total">%%ORDER_AMOUNT%%</span>
<span id="gts-o-discounts">%%GLOBAL_CouponDiscount%%</span>
<span id="gts-o-shipping-total">%%GLOBAL_ShippingPrice%%</span>
<span id="gts-o-tax-total">%%GLOBAL_TaxCost%%</span>
<span id="gts-o-est-ship-date"></span>
<script>
var today = new Date();
var tomorrow = new Date();
tomorrow.setDate(today.getDate()+3);
if(tomorrow.getMonth() <= 8){
var fecha = tomorrow.getFullYear()+'-'+'0'+(tomorrow.getMonth()+1)+'-'+tomorrow.getDate();
} else{
var fecha = tomorrow.getFullYear()+'-'+(tomorrow.getMonth()+1)+'-'+tomorrow.getDate();
}
document.getElementById("gts-o-est-ship-date").innerHTML = fecha;
</script>
<span id="gts-o-est-delivery-date"></span>
<script>
var today2 = new Date();
var tomorrow2 = new Date();
var j =document.getElementById("gts-o-country").innerHTML;
if( j != 'US'){
if(
tomorrow2.setDate(today.getDate()+4);
if(tomorrow2.getMonth() <= 8){
var fecha2 = tomorrow2.getFullYear()+'-'+'0'+(tomorrow2.getMonth()+1)+'-'+tomorrow2.getDate();
} else{
var fecha2 = tomorrow2.getFullYear()+'-'+(tomorrow2.getMonth()+1)+'-'+tomorrow2.getDate();
}
document.getElementById("gts-o-est-delivery-date").innerHTML = fecha2;
}else{
tomorrow2.setDate(today.getDate()+20);
if(tomorrow2.getMonth() <= 8){
var fecha2 = tomorrow2.getFullYear()+'-'+'0'+(tomorrow2.getMonth()+1)+'-'+tomorrow2.getDate();
} else{
var fecha2 = tomorrow2.getFullYear()+'-'+(tomorrow2.getMonth()+1)+'-'+tomorrow2.getDate();
}
document.getElementById("gts-o-est-delivery-date").innerHTML = fecha2;
}
</script>
<span id="gts-o-has-preorder">N</span>
<span id="gts-o-has-digital">N</span>
<!-- end order and merchant information -->
<!-- start repeated item specific information -->
<!-- item example: this area repeated for each item in the order -->
<span class="gts-item">
<span class="gts-i-name">%%GLOBAL_ProductName%%</span>
<span class="gts-i-price">%%GLOBAL_ProductPrice%%</span>
<span class="gts-i-quantity">%%GLOBAL_ProductQuantity%%</span>
<span class="gts-i-prodsearch-id">%%GLOBAL_ProductId%%</span>
<span class="gts-i-prodsearch-store-id">483911</span>
<span class="gts-i-prodsearch-country">US</span>
<span class="gts-i-prodsearch-language">en_US</span>
</span>
<!-- end item 1 example -->
<!-- end repeated item specific information -->
</div>
<!-- END Google Trusted Stores Order -->
I put this under the order.html I'm checking some other options because your code is uncomplete on the delivery date and ship date. when I spoke with some bigcommerce people they said that this variables are populated from customer information that is given when you are platinum ( which means that they don't even exist on bigcommerce )
Please let me know if you find something else or if it works for you. also please don't forget to purchase and install your own ssl
In my experience with Bigcommerce this is not possible. They have restricted the data which is required for GTS to only be available in the code that is output by their system, and not in other files. Basically, even if we knew what the variables were I don't believe they would work because they aren't a global scope.
I would guess that if you can use GTS to sell your products, the small price increase from their Gold to platinum level will quickly be made up in your sales.