formData get() Doesn't seem to work in Safari - safari

This is my code. It works in Firefox and Chrome but not Safari. I get no errors.
<script>
var cleanData = new FormData();
cleanData.append("test", "test");
alert(cleanData.get("test"));
</script>
Does anyone know a workaround?

Apparently, Safari has no means of getting values stored in FormData objects at this time. There is no workaround at this time, and apparently it's not practical to polyfill.
Sorry :(
Notes:
https://developer.mozilla.org/en-US/docs/Web/API/FormData/get#Browser_compatibility
https://www.bountysource.com/issues/27573236-is-it-possible-to-polyfill-missing-formdata-methods

I solved this by conditionally (if Safari is the browser) iterating through the elements property of an actual form. For all other browser, my wrapper just iterates through FormData entries(). The end result of my function, in either case, is a simple javascript object (JSON) which amounts to name/value pairs.
function FormDataNameValuePairs(FormName)
{
var FormDaytaObject={};
var FormElement=$('#'+FormName).get(0);
if (IsSafariBrowser())
{
var FormElementCollection=FormElement.elements;
//console.log('namedItem='+FormElementCollection.namedItem('KEY'));
var JQEle,EleType;
for (ele=0; (ele < FormElementCollection.length); ele++)
{
JQEle=$(FormElementCollection.item(ele));
EleType=JQEle.attr('type');
// https://github.com/jimmywarting/FormData/blob/master/FormData.js
if ((! JQEle.attr('name')) ||
(((EleType == 'checkbox') || (EleType == 'radio')) &&
(! JQEle.prop('checked'))))
continue;
FormDaytaObject[JQEle.attr('name')]=JQEle.val();
}
}
else
{
var FormDayta=new FormData(FormElement);
for (var fld of FormDayta.entries())
FormDaytaObject[fld[0]]=fld[1];
}
return FormDaytaObject;
}
where IsSafariBrowser() is implemented by whatever your favorite method is, but I chose this:
function IsSafariBrowser()
{
var VendorName=window.navigator.vendor;
return ((VendorName.indexOf('Apple') > -1) &&
(window.navigator.userAgent.indexOf('Safari') > -1));
}
Example usage in OP's case, assuming that you have an actual form called CleanDataForm instead of creating a FormData from scratch:
var cleanData=FormDataNameValuePairs('CleanDataForm');
alert(cleanData.test);

Related

Adding embedded mode in docusaurus

I am using docusaurus 1.14.4
I need to create embedded mode for each document which remove header, footer and left navigation.
Page url look like this http://localhost:3000/...../?mode=emb
I figure out a way by adding this piece of script to each md file
<script>
function getParameterByName(name) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
var mode = getParameterByName('mode');
if (mode === 'emb') {
setTimeout(()=>{
let list = ['fixedHeaderContainer', 'docsNavContainer', 'nav-footer', 'docs-prevnext'];
for (var itemClassName of list) {
var item = document.getElementsByClassName(itemClassName)[0]
item.parentNode.removeChild(item)
}
document.getElementsByClassName('navPusher')[0].style.paddingTop = 0;
document.getElementsByClassName('mainContainer')[0].style.paddingTop = 0;
}, 0)
}
</script>
It work but does not look like a proper way. Can anyone suggest a better way?
Docusaurus maintainer here. There's no supported way of doing this. May I know what your motivations for doing this are?

How to prevent closing of cell edit mode on validation errors with custom vue components in ag-grid

I have succesfully rendered my own component as the cellEditor and would like and on-leave I would like it to try to validate the value and prevent the closing if it fails.
If I look at this then https://www.ag-grid.com/javascript-grid-cell-editing/#editing-api there's cancelable callback functions for editing. But in this callback function is there a way to access the current instantiated component? I would think that would be the easiest way to handle this.
I'm using vee-validate so the validation function is async, just to keep in mind.
Use Full row editing.
Create a global variable like
var problemRow = -1;
Then Subscribe to this events:
onRowEditingStarted: function (event) {
if (problemRow!=-1 && event.rowIndex!=problemRow) {
gridOptions.api.stopEditing();
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
},
onRowEditingStopped: function (event) {
if (problemRow==-1) {
if (event.data.firstName != "your validation") {
problemRow = event.rowIndex
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
}
if (problemRow == event.rowIndex) {
if (event.data.firstName != "your validation") {
problemRow = event.rowIndex
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
else{
problemRow=-1;
}
}
},
I had a similar issue - albeit in AngularJS and the non-Angular mode for ag-grid - I needed to prevent the navigation when the cell editor didn't pass validation.
The documentation is not very detailed, so in the end I added a custom cell editor with a form wrapped around the input field (to handle the niceties such as red highlighting etc), and then used Angular JS validation. That got me so far, but the crucial part was trying to prevent the user tabbing out or away when the value was invalid so the user could at least fix the issue.
I did this by adding a value parser when adding the cell, and then within that if the value was invalid according to various rules, throw an exception. Not ideal, I know - but it does prevent ag-grid from trying to move away from the cell.
I tried loads of approaches to solving this - using the tabToNextCell events, suppressKeyboardEvent, navigateToNextCell, onCellEditingStopped - to name a few - this was the only thing that got it working correctly.
Here's my value parser, for what it's worth:
var codeParser = function (args) {
var cellEditor = _controller.currentCellEditor.children['codeValue'];
var paycodeId = +args.colDef.field;
var paycodeInfo = _controller.paycodes.filter(function (f) { return f.id === paycodeId; })[0];
// Check against any mask
if (paycodeInfo && paycodeInfo.mask) {
var reg = new RegExp("^" + paycodeInfo.mask + '$');
var match = args.newValue.match(reg);
if (!match) {
$mdToast.show($mdToast.simple().textContent('Invalid value - does not match paycode format.').position('top right').toastClass('errorToast'))
.then(function(r) {
_controller.currentCellEditor.children['codeValue'].focus();
});
throw 'Invalid value - does not match paycode format.';
}
}
return true;
};
The _controller.currentCellEditor value is set during the init of the cell editor component. I do this so I can then refocus the control after the error has been shown in the toast:
CodeValueEditor.prototype.init = function (params) {
var form = document.createElement('form');
form.setAttribute('id', 'mainForm');
form.setAttribute('name', 'mainForm');
var input = document.createElement('input');
input.classList.add('ag-cell-edit-input');
input.classList.add('paycode-editor');
input.setAttribute('name', 'codeValue');
input.setAttribute('id', 'codeValue');
input.tabIndex = "0";
input.value = params.value;
if (params.mask) {
input.setAttribute('data-mask', params.mask);
input.setAttribute('ng-pattern','/^' + params.mask + '$/');
input.setAttribute('ng-class',"{'pattern-error': mainForm.codeValue.$error.pattern}");
input.setAttribute('ng-model', 'ctl.currentValue');
}
form.appendChild(input);
this.container = form;
$compile(this.container)($scope);
_controller.currentValue = null;
// This is crucial - we can then reference the container in
// the parser later on to refocus the control
_controller.currentCellEditor = this.container;
$scope.$digest();
};
And then cleared in the grid options onCellEditingStopped event:
onCellEditingStopped: function (event) {
$scope.$apply(function() {
_controller.currentCellEditor = null;
});
},
I realise it's not specifically for your components (Vue.js) but hopefully it'll help someone else. If anyone has done it a better way, I'm all ears as I don't like throwing the unnecessary exception!

VueJS handle URL fragment to action without Vue Router and without jQuery

I am currently using VueJS 2.x and have not gone VueRouter yet (and am not able anyway).
Quite simply, I want Vue to detect a URL fragment like https://example.com/mypage#record-17 and for example simulate the click of the following modal link:
<a :id="record.id" :click="openModal(record.id)">Open this record</a>
Should I just parse window.location myself or is there a more elegant way to do it? I also want to not use jQuery.
This is our script for parsing args from the hash. It lets you put a query string after the hash, that will be parsed by the script. If, like us, you also need to pass an url that you don't want parsed, put it at the end in a 'src' argument.
var args = (function () {
var returnVal = {};
var argString = window.location.hash;
//everything after src belongs as part of the url, not to be parsed
var argsAndSrc = argString.split(/src=/);
returnVal["src"] = argsAndSrc[1];
//everything before src is args for this page.
var argArray = argsAndSrc[0].split("&");
for (var i = 0; i < argArray.length; i++) {
var nameVal = argArray[i].split("=");
//strip the hash
if (i == 0) {
var name = nameVal[0];
nameVal[0] = name.slice(1);
}
returnVal[nameVal[0]] = decodeURI(nameVal[1]);
}
return returnVal
})();

Phantomjs dump dom object

I'm new to Phantomjs. For debugging on a remote server, I often want to dump a DOM object to look at the structure (similar to Data::Dumper in Perl). This currently is for scraping a couple of sites.
I've thought JSON.stringify may help with this, but it still displays an object name like "[object HTMLDocument]"
Edit: I have also looked at JavaScript: how to serialize a DOM element as a string to be used later? , but I can't seem to inject jquery in phantomjs (still looking for a solution to that, and would prefer no depencencies), and the other answer doesn't seem to work. As I assume it would be a common case for Phantom to analyse the DOM, I thought it would be common for phantom users to have a solution to this.
var page = require('webpage').create();
var system = require('system');
page.onConsoleMessage = function(msg) {
console.log( msg );
}
page.open('http://www.test.com', function(status) {
if(status !== "success") {
console.log( status );
} else {
page.evaluate(function() {
var headline = document.querySelectorAll('div');
console.log( JSON.stringify( headline ) ); // HERE???
});
}
phantom.exit();
});
Is there any way to do this, or am I approaching this wrong ?
in page.evaluate(), you can use XMLSerializer.serializeToString() to convert whatever DOM node you want to string.
page.evaluate(function() {
var s = new XMLSerializer();
return s.serializeToString(document.getElementById('div'));
});
I haven't tried it with "querySelectorAll", since it may return array instead of standalone DOM node, but it definitely works for DOM nodes.
MDN Link

How do I force razor to switch back to client side code?

I've got the following code in one of my views
#if (ViewBag.LoginInfo != null)
{
var loginToken = "#ViewBag.LoginInfo.Token";
var loginUser = "#ViewBag.LoginInfo.UserNameJs";
var notifyUrl = "#ViewBag.LoginInfo.NotificationUrl";
}
The code between { } should be rendered to the page as javascript, however it seems to be getting run as serverside code. I'm aware razor switches back to client code when it sees html in this case the code is valid as C# and javascript. How to I force everthing between { } to be written to the page as javasript?
Thanks
Alternatively use #:
#if (ViewBag.LoginInfo != null)
{
#:var loginToken = #Html.Raw(Json.Encode(ViewBag.LoginInfo.Token);
#:var loginUser = #Html.Raw(Json.Encode(ViewBag.LoginInfo.UserNameJs);
#:var notifyUrl = #Html.Raw(Json.Encode(ViewBag.LoginInfo.NotificationUrl);
}
You could wrap them in <text> tags:
#if (ViewBag.LoginInfo != null)
{
<text>
var loginToken = #Html.Raw(Json.Encode(ViewBag.LoginInfo.Token);
var loginUser = #Html.Raw(Json.Encode(ViewBag.LoginInfo.UserNameJs);
var notifyUrl = #Html.Raw(Json.Encode(ViewBag.LoginInfo.NotificationUrl);
</text>
}
Also notice how I have safely encoded the values. Your example will produce invalid javascript if for example your token contains the " character. You should never be mixing javascript and server side values without using a safe serializer as shown in my example.