How to get tree of svg inserted to the DOM as text - text

I have embeded svg that I created dynamicaly using ajax
$.ajax({
url: 'file.svg',
dataType: 'text',
success: function(svg) {
var svg = $(svg).appendTo('body');
var shape = svg.find('g#shape');
// how to get shape as text.
}
});
How can I get svg Tree for instance a group with few paths as text the same as html() work in jQuery?

You can use XMLSerializer to serialise a node. Something like this...
var XMLS = new XMLSerializer();
var string = XMLS.serializeToString(node);

Depending on your browser, it can use one of two serializer:
function xmltostring(domElem) { // Input the NODE of the DOM element
if (window.XMLSerializer) { // FF, Chrome, IE10 has an internal serializer
var XMLS = new XMLSerializer();
var xmlString = XMLS.serializeToString(domElem);
} else if (window.ActiveXObject){ // IE9 uses ActiveX
var xmlString = domElem.xml;
}
return xmlString;
}
Note: Works on Safari too. IE8 and below cannot handle SVG natively (needs plugin), untested with this function.

I found a way, I wrote this plugin that return the text of SVG, probably will work with any xml embeded into html DOM.
$.fn.xml = function() {
function serialize(node) {
var i;
var text = '<' + node.nodeName;
for(i = 0; i < node.attributes.length; ++i) {
text += ' ' + node.attributes[i].name + '="' +
node.attributes[i].value + '"';
}
text += '>';
if (node.childNodes.length) {
for (i = 0; i < node.childNodes.length; ++i) {
if (node.childNodes[i] instanceof Text) {
text += node.childNodes[i].wholeText
} else if (node.childNodes[i] instanceof SVGElement) {
text += serialize(node.childNodes[i]);
}
}
}
return text + '</' + node.nodeName + '>';;
}
return serialize(this[0]);
};

Related

How to change the default values when add link Sharepoint 2013

In Add Link page, is it possible to change the default values like title, address, show these links to, by using URL parameters?
According to this, it seems possible in sharepoint2010. Does anyone know whether it works in 2013??
If not, is it possible to add a link by post REST API??
This problem can be solved by the steps below.
Add a custom action. Just follow the steps here.
In my case code is as below
SP.SOD.executeFunc("callout.js", "Callout", function() {
var itemCtx = {};
itemCtx.Templates = {};
itemCtx.BaseViewID = 'Callout';
// Define the list template type
itemCtx.ListTemplateType = 101;
itemCtx.Templates.Footer = function(itemCtx) {
// context, custom action function, show the ECB menu (boolean)
return CalloutRenderFooterTemplate(itemCtx, AddCustomAction, true);
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(itemCtx);
});
function AddCustomAction(renderCtx, calloutActionMenu) {
// Add your custom action
calloutActionMenu.addAction(new CalloutAction({
text: "FAVORITE",
// tooltip: 'This is your custom action',
onClickCallback: function() {
CreateCustomNewQuickLink(renderCtx.CurrentItem.FileLeafRef, renderCtx.CurrentItem.FileRef);
}
}));
// Show the default document library actions
CalloutOnPostRenderTemplate(renderCtx, calloutActionMenu);
}
function CreateCustomNewQuickLink(title, url) {
var urlAddress = $(location).attr('protocol') + "//" + $(location).attr('host') + '/_Layouts/quicklinksdialogformTEST.aspx?Mode=Link' +
'&title=' + encodeURIComponent(title) +
'&url=' + encodeURIComponent(url);
ShowNewQuicklinkPopup(urlAddress, PageRefreshOnDialogClose);
}
Create a new add link page which is copied from "quicklinksdialogform.aspx". I add some javascript as below.
$(init)
function init() {
var args = new Object();
args = GetUrlParms();
if (args["title"] != undefined) {
$(".ms-long")[0].value = decodeURIComponent(args["title"]);
}
if (args["url"] != undefined) {
$(".ms-long")[1].value = decodeURIComponent(args["url"]);
}
}
function GetUrlParms() {
var args = new Object();
var query = location.search.substring(1);
var pairs = query.split("&");
for (var i = 0; i < pairs.length; i++) {
var pos = pairs[i].indexOf('=');
if (pos == -1) continue;
var argname = pairs[i].substring(0, pos);
var value = pairs[i].substring(pos + 1);
args[argname] = unescape(value);
}
return args;
}
It works like below

Correct way to export data to excel?

I am currently trying to export some data from my application in either Excel or CSV. What is the best way to accomplish this? Should I export from the backend, or export once I have the data client side using a library within Angular 2? My Web API 2 controller currently produces a list and then sends it as JSON to the front end.
That all works, I am just struggling with exporting the list.
Here is a sample of what I am doing
[HttpGet]
[Route("/api/preview/{item}")]
public IActionResult Preview(string item)
{
if (item!= null)
{
var preview = _context.dbPreview.FromSql("Exec sampleStoredProcedure {0}, 1", item).ToList();
return Ok(preview);
}
}
That is how I am generating my data that is sent to Angular 2.
I can provide any Angular 2 code if it is necessary but it is just a normal service. Was not sure if there was some library that worked well with Angular 2 to do an export. I've seen some things for javascript but alaSQL but it does not seem like it would work with Angular 2.
Any ideas?
I've looked at the source code from PrimeNG DataTable and I think you can use the exportCSV code for exporting a csv of your data.
The "trick" is to generate a string starting with data:text/csv;charset=utf-8 and make this downloadable by the user.
Something like the following code should work for you (maybe you need to modify it a bit so it fits to your data).
Most of the code is copied from PrimeNG except the download method. That method is copied from a SO answer.
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app works!';
csvSeparator = ';';
value = [
{ name: 'A3', year: 2013, brand: 'Audi' },
{ name: 'Z3', year: 2015, brand: 'BMW' }
];
columns = [
{ field: 'name', header: 'Name' },
{ field: 'year', header: 'Production data' },
{ field: 'brand', header: 'Brand' },
];
constructor() {
console.log(this.value);
this.exportCSV('cars.csv'); // just for show casing --> later triggered by a click on a button
}
download(text, filename) {
let element = document.createElement('a');
element.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
exportCSV(filename) {
let data = this.value, csv = '';
// csv = "data:text/csv;charset=utf-8,";
//headers
for (let i = 0; i < this.columns.length; i++) {
if (this.columns[i].field) {
csv += this.columns[i].field;
if (i < (this.columns.length - 1)) {
csv += this.csvSeparator;
}
}
}
//body
this.value.forEach((record, j) => {
csv += '\n';
for (let i = 0; i < this.columns.length; i++) {
if (this.columns[i].field) {
console.log(record[this.columns[i].field]);
// resolveFieldData seems to check if field is nested e.g. data.something --> probably not needed
csv += record[this.columns[i].field]; //this.resolveFieldData(record, this.columns[i].field);
if (i < (this.columns.length - 1)) {
csv += this.csvSeparator;
}
}
}
});
// console.log(csv);
// window.open(encodeURI(csv)); // doesn't display a filename!
this.download(csv, filename);
}
// resolveFieldData(data: any, field: string): any {
// if(data && field) {
// if(field.indexOf('.') == -1) {
// return data[field];
// }
// else {
// let fields: string[] = field.split('.');
// let value = data;
// for(var i = 0, len = fields.length; i < len; ++i) {
// value = value[fields[i]];
// }
// return value;
// }
// }
// else {
// return null;
// }
// }
}
AWolfs answer got me on the right track but I did some tweaking to get it working with Internet Explorer.
This function converts my array to my string for my csv file. (I had to create a new object that was my column headers). I then just pass the data that is generated by my service to the function and it does the parsing for me. For more complex data I believe you would need to do some additional logic but I have basic text so it all worked out for me.
exportCSV(filename, CsvData) {
let data = CsvData, csv = '';
console.log(data);
//headers
for (let i = 0; i < this.columns.length; i++) {
if (this.columns[i].field) {
csv += this.columns[i].field;
if (i < (this.columns.length - 1)) {
csv += this.csvSeparator;
}
}
}
//body
CsvData.forEach((record, j) => {
csv += '\n';
for (let i = 0; i < this.columns.length; i++) {
if (this.columns[i].field) {
console.log(record[this.columns[i].field]);
csv += record[this.columns[i].field];
if (i < (this.columns.length - 1)) {
csv += this.csvSeparator;
}
}
}
});
this.DownloadFile(csv, filename);
}
That was pretty much the same as AWolfs answer but I had to make some modifications to the DownloadFile function to get it to work with additional browsers. This function just accepts the huge string that makes up your .CSV file and the filename.
DownloadFile(text, filename) {
console.log(text);
var blob = new Blob([text], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, filename);
}
else //create a link and click it
{
var link = document.createElement("a");
if (link.download !== undefined) // feature detection
{
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}
This code needs cleaned up but I wanted to update my question with an answer for anyone who was struggling with the same thing. This should at least get you started. This works in both Chrome and IE.
Thanks.

Polymer add style dynamically

In a polymer control,'my-grid', I'm trying to add style via the below code:
var styleElement = document.createElement('style', 'custom-style');
styleElement.innerHTML = cssText;
Polymer.StyleDefaults.addStyle(styleElement);
Here, the cssText can be string like
.oc-col-id-0{
flex-basis: var(--oc-col-id-0-flex-basis);
-webkit-flex-basis: var(--oc-col-id-0-flex-basis);
}
.oc-col-id-1{
flex-basis: var(--oc-col-id-1-flex-basis);
-webkit-flex-basis: var(--oc-col-id-1-flex-basis);
}
Without this custom variables, I can append the styleElement by
this.$.gridContainer.appendChild(styleElement);
But however, since there are custom variables, I'm not sure how to fix this issue.
After the element is attached, I can't change the --oc-col-id-0-flex-basis value via
this.customStyle['--oc-col-id-0-flex-basis'] = maxWidth + "px";
this.updateStyles();
It looks that the style variables are not applied to the element.
I'm not sure if there is any way to dynamically add/modify the style of the element. I'm not sure if I'm on the right track.
This is what I do in the end to inject the style class dynamically. It solved my problem so far.
var style = this._styles[0];
var text = style.textContent;
var cssText = "";
for (var id of ids)
{
var classStyle = ".col-id-" + id;
var variableProperty = "--col-id-" + id + "-flex-basis";
if (text.indexOf(classStyle) == -1)
{
cssText += classStyle + "{ flex-basis: var(" + variableProperty + ", auto); -webkit-flex-basis: var(" + variableProperty + ", auto);} ";
}
if (this._ownStylePropertyNames.indexOf(variableProperty) == -1)
{
this._ownStylePropertyNames.push(variableProperty);
}
}
if (cssText.length > 0)
{
style.textContent += " " + cssText;
style.__cssRules = null; //trick for rulesForStyle method in Polymer.html
}

d3.js- noob- how to bind data to path from external svg by path ID?

I'm attempting to make a chloropleth map using an SVG file of the counties and a csv of data for each of these. I'm new to D3 and working off of an example that used geoJSON.(thank you Scott Murray).
The example ties the data to the shapes like so:
d3.json("us-states.json", function(json) {
//Merge the ag. data and GeoJSON
//Loop through once for each ag. data value
for (var i = 0; i < data.length; i++) {
var dataState = data[i].state; //Grab state name
var dataValue = parseFloat(data[i].value); //Grab data value, and convert from string to float
//Find the corresponding state inside the GeoJSON
for (var j = 0; j < json.features.length; j++) {
var jsonState = json.features[j].properties.name;
if (dataState == jsonState) {
//Copy the data value into the JSON
json.features[j].properties.value = dataValue;
//Stop looking through the JSON
break;
}
}
}
//Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("fill", function(d) {
//Get data value
var value = d.properties.value;
if (value) {
//If value exists…
return color(value);
} else {
//If value is undefined…
return "#ccc";
}
});
But I am having trouble in adapting this to the svg. I don't need to have it create the paths- they're already there, but how would one write essentially: " if data.County == path id, bind that row's data to the path" ?
Any help is much appreciated!!
Take a look at https://github.com/mbostock/d3/wiki/Selections#wiki-datum.
Do something like:
// Where each path has an id
var paths = d3.selectAll('.my-paths path'),
elm,
data = [] // your data here,
your_criteria_here;
data.forEach(function (x, i, a) {
your_criteria_here = x.criteria;
// No data is available for the elements in this case yet
// #see https://github.com/mbostock/d3/wiki/Selections#wiki-each
paths.each(function (d, i) {
// Wrap dom element in d3 selection
elm = d3.select(this);
if (elm.attr('id') == your_criteria_here) {
// Do something here ...
}
});
});
Note this example makes use of [].forEach which is an ecmascript 5 feature (#see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach)

Display only anchors

Could you advise me with writing a greasemonkey script displaying only anchors () in a web page and deleting everything else?
thank you
This code will wipe out everything but a list of the href's from links (added line breaks for clarity):
var links = document.querySelectorAll ("a");
//--- Build up new body, that will just display hrefs.
var newPageStr = "";
for (var J=0, L=links.length; J < L; ++J) {
//--- Skip links with empty href's.
var href = links[J].href;
if ( /\w/.test (href) ) {
newPageStr += '' + href + '<br>';
}
}
//--- Replace everything on the page with the link list.
document.close ();
document.open ();
document.write (newPageStr);
document.close ();
Update:
Since document.write() seems to flake in the GM environment, here's a DOM-based alternative:
var links = document.querySelectorAll ("a");
//--- Build up new body, that will just display hrefs.
var newPageStr = "";
for (var J=0, L=links.length; J < L; ++J) {
//--- Skip links with empty href's.
var href = links[J].href;
if ( /\w/.test (href) ) {
newPageStr += '' + href + '<br>';
}
}
//--- Erase everything from the page's body:
var b = document.body;
var p = b.parentNode;
p.removeChild (b);
//--- Add our new link list.
var newB = document.createElement ("BODY");
newB.innerHTML = newPageStr;
p.appendChild (newB);
var tags = document.getElementsByTagName('*');
for (var i = 0; i < tags.length; i++) {
if (tags[i].tagName != 'A') {
tags[i].style.color = 'transparent';
tags[i].style.background = 'none';
tags[i].style.border = 'none';
}
}

Resources