Database of file extensions to file type/language mappings - programming-languages

vscode uses a nice schema for file extension to language mapping:
https://code.visualstudio.com/docs/languages/identifiers
"files.associations": {
"*.myphp": "php"
}
"languages": [{
"id": "java",
"extensions": [ ".java", ".jav" ],
"aliases": [ "Java", "java" ]
}]
Tools like prismjs, have built-in support for hundreds of languages.
But I can't find a database of common extension to language mapping anywhere. Note I don't care about mime types. In my case I want have a built-in (actually, it'd ideally be driven off a webapi) set of mappings.
I've searched the vscode and found the code that deals with the mappings it handles (/src/vs/editor/common/services/languagesRegistry.ts) but it appears to load the mapping from the extensions that are installed.
IOW, I want to generate (or find!) a JSON document using the above schema with all 199 languages that prismjs supports.
Any suggestions?

lang-map, a nodejs module makes it easy to go from either file extension to language or language to supported extensions.
https://github.com/jonschlinkert/lang-map
I've successfully used this to generate a JSON doc using the vscode schema.
Probably aint pretty (not a javascript pro), but it works:
// Imports file-extension to langauge mapping from both
// prismjs and lang-map and outputs a JSON document that
// follows the vscode schema for extension mapping.
// PrismJS language definitions trump for my solution.
const fs = require('fs');
var map = require('lang-map');
var components = require('prismjs/components.js');
// vscode files.associations is not an array. Use a dictionary instead.
var assocDict = {};
var languages = [];
for (var key in components.languages) {
if (components.languages.hasOwnProperty(key) && key != 'meta') {
var language = components.languages[key];
var langTemp = {
id : key
};
// vscode doesn't support title, but I want to use it
if (typeof language.title != 'undefined')
langTemp.title = language.title;
if (typeof language.alias != 'undefined'){
if (Array.isArray(language.alias)){
langTemp.aliases = language.alias;
}
else{
langTemp.aliases = ['.' + language.alias];
}
}
var extensions = [];
map.extensions(key).forEach(ext =>{
// Add it to the extnsions for this langauge defn
extensions.push('.' + ext);
// also add it to the files.associations dictionary
var pattern = '*.' + ext;
var assoc = {
pattern : key
};
assocDict[pattern] = key;
});
langTemp.extensions = extensions;
languages.push(langTemp);
}
}
// create JSON doc conforming to vscode spec. associations is not an array
// languages is
var output = {
'files.associations' : assocDict,
'languages' : languages
};
var file = "../winforms/WinPrint.Core/Properties/languages.json";
fs.writeFile(file, JSON.stringify(output, null, ' '), function (err) {
if (err) {
return console.log(err);
}
console.log("Wrote " + Object.keys(assocDict).length + " file-type associations and " + languages.length + " language defs to " + file);
});
I also found this, which I may just use instead:
https://github.com/blakeembrey/language-map

Related

Getting an error while saving JSON in to mongodb [duplicate]

How do I display the content of a JavaScript object in a string format like when we alert a variable?
The same formatted way I want to display an object.
Use native JSON.stringify method.
Works with nested objects and all major browsers support this method.
str = JSON.stringify(obj);
str = JSON.stringify(obj, null, 4); // (Optional) beautiful indented output.
console.log(str); // Logs output to dev tools console.
alert(str); // Displays output using window.alert()
Link to Mozilla API Reference and other examples.
obj = JSON.parse(str); // Reverses above operation (Just in case if needed.)
Use a custom JSON.stringify replacer if you
encounter this Javascript error
"Uncaught TypeError: Converting circular structure to JSON"
If you want to print the object for debugging purposes, use the code:
var obj = {
prop1: 'prop1Value',
prop2: 'prop2Value',
child: {
childProp1: 'childProp1Value',
},
}
console.log(obj)
will display:
Note: you must only log the object. For example, this won't work:
console.log('My object : ' + obj)
Note ': You can also use a comma in the log method, then the first line of the output will be the string and after that, the object will be rendered:
console.log('My object: ', obj);
var output = '';
for (var property in object) {
output += property + ': ' + object[property]+'; ';
}
alert(output);
console.dir(object):
Displays an interactive listing of the properties of a specified JavaScript object. This listing lets you use disclosure triangles to examine the contents of child objects.
Note that the console.dir() feature is non-standard. See MDN Web Docs
Try this:
console.log(JSON.stringify(obj))
This will print the stringify version of object. So instead of [object] as an output you will get the content of object.
Well, Firefox (thanks to #Bojangles for detailed information) has Object.toSource() method which prints objects as JSON and function(){}.
That's enough for most debugging purposes, I guess.
If you want to use alert, to print your object, you can do this:
alert("myObject is " + myObject.toSource());
It should print each property and its corresponding value in string format.
If you would like to see data in tabular format you can use:
console.table(obj);
Table can be sorted if you click on the table column.
You can also select what columns to show:
console.table(obj, ['firstName', 'lastName']);
You can find more information about console.table here
Function:
var print = function(o){
var str='';
for(var p in o){
if(typeof o[p] == 'string'){
str+= p + ': ' + o[p]+'; </br>';
}else{
str+= p + ': { </br>' + print(o[p]) + '}';
}
}
return str;
}
Usage:
var myObject = {
name: 'Wilson Page',
contact: {
email: 'wilson#hotmail.com',
tel: '123456789'
}
}
$('body').append( print(myObject) );
Example:
http://jsfiddle.net/WilsonPage/6eqMn/
In NodeJS you can print an object by using util.inspect(obj). Be sure to state the depth or you'll only have a shallow print of the object.
Simply use
JSON.stringify(obj)
Example
var args_string = JSON.stringify(obj);
console.log(args_string);
Or
alert(args_string);
Also, note in javascript functions are considered as objects.
As an extra note :
Actually you can assign new property like this and access it console.log or display it in alert
foo.moo = "stackoverflow";
console.log(foo.moo);
alert(foo.moo);
To print the full object with Node.js with colors as a bonus:
console.dir(object, {depth: null, colors: true})
Colors are of course optional, 'depth: null' will print the full object.
The options don't seem to be supported in browsers.
References:
https://developer.mozilla.org/en-US/docs/Web/API/Console/dir
https://nodejs.org/api/console.html#console_console_dir_obj_options
NB:
In these examples, yourObj defines the object you want to examine.
First off my least favorite yet most utilized way of displaying an object:
This is the defacto way of showing the contents of an object
console.log(yourObj)
will produce something like :
I think the best solution is to look through the Objects Keys, and then through the Objects Values if you really want to see what the object holds...
console.log(Object.keys(yourObj));
console.log(Object.values(yourObj));
It will output something like :
(pictured above: the keys/values stored in the object)
There is also this new option if you're using ECMAScript 2016 or newer:
Object.keys(yourObj).forEach(e => console.log(`key=${e} value=${yourObj[e]}`));
This will produce neat output :
The solution mentioned in a previous answer: console.log(yourObj) displays too many parameters and is not the most user friendly way to display the data you want. That is why I recommend logging keys and then values separately.
Next up :
console.table(yourObj)
Someone in an earlier comment suggested this one, however it never worked for me. If it does work for someone else on a different browser or something, then kudos! Ill still put the code here for reference!
Will output something like this to the console :
Here's a way to do it:
console.log("%o", obj);
Use this:
console.log('print object: ' + JSON.stringify(session));
As it was said before best and most simply way i found was
var getPrintObject=function(object)
{
return JSON.stringify(object);
}
(This has been added to my library at GitHub)
Reinventing the wheel here! None of these solutions worked for my situation. So, I quickly doctored up wilsonpage's answer. This one is not for printing to screen (via console, or textfield or whatever). It does work fine in those situations and works just fine as the OP requested, for alert. Many answers here do not address using alert as the OP requested. Anyhow, It is, however, formatted for data transport. This version seems to return a very similar result as toSource(). I've not tested against JSON.stringify, but I assume this is about the same thing. This version is more like a poly-fil so that you can use it in any environment. The result of this function is a valid Javascript object declaration.
I wouldn't doubt if something like this was already on SO somewhere, but it was just shorter to make it than to spend a while searching past answers. And since this question was my top hit on google when I started searching about this; I figured putting it here might help others.
Anyhow, the result from this function will be a string representation of your object, even if your object has embedded objects and arrays, and even if those objects or arrays have even further embedded objects and arrays. (I heard you like to drink? So, I pimped your car with a cooler. And then, I pimped your cooler with a cooler. So, your cooler can drink, while your being cool.)
Arrays are stored with [] instead of {} and thus dont have key/value pairs, just values. Like regular arrays. Therefore, they get created like arrays do.
Also, all string (including key names) are quoted, this is not necessary unless those strings have special characters (like a space or a slash). But, I didn't feel like detecting this just to remove some quotes that would otherwise still work fine.
This resulting string can then be used with eval or just dumping it into a var thru string manipulation. Thus, re-creating your object again, from text.
function ObjToSource(o){
if (!o) return 'null';
var k="",na=typeof(o.length)=="undefined"?1:0,str="";
for(var p in o){
if (na) k = "'"+p+ "':";
if (typeof o[p] == "string") str += k + "'" + o[p]+"',";
else if (typeof o[p] == "object") str += k + ObjToSource(o[p])+",";
else str += k + o[p] + ",";
}
if (na) return "{"+str.slice(0,-1)+"}";
else return "["+str.slice(0,-1)+"]";
}
Let me know if I messed it all up, works fine in my testing. Also, the only way I could think of to detect type array was to check for the presence of length. Because Javascript really stores arrays as objects, I cant actually check for type array (there is no such type!). If anyone else knows a better way, I would love to hear it. Because, if your object also has a property named length then this function will mistakenly treat it as an array.
EDIT: Added check for null valued objects. Thanks Brock Adams
EDIT: Below is the fixed function to be able to print infinitely recursive objects. This does not print the same as toSource from FF because toSource will print the infinite recursion one time, where as, this function will kill it immediately. This function runs slower than the one above, so I'm adding it here instead of editing the above function, as its only needed if you plan to pass objects that link back to themselves, somewhere.
const ObjToSource=(o)=> {
if (!o) return null;
let str="",na=0,k,p;
if (typeof(o) == "object") {
if (!ObjToSource.check) ObjToSource.check = new Array();
for (k=ObjToSource.check.length;na<k;na++) if (ObjToSource.check[na]==o) return '{}';
ObjToSource.check.push(o);
}
k="",na=typeof(o.length)=="undefined"?1:0;
for(p in o){
if (na) k = "'"+p+"':";
if (typeof o[p] == "string") str += k+"'"+o[p]+"',";
else if (typeof o[p] == "object") str += k+ObjToSource(o[p])+",";
else str += k+o[p]+",";
}
if (typeof(o) == "object") ObjToSource.check.pop();
if (na) return "{"+str.slice(0,-1)+"}";
else return "["+str.slice(0,-1)+"]";
}
Test:
var test1 = new Object();
test1.foo = 1;
test1.bar = 2;
var testobject = new Object();
testobject.run = 1;
testobject.fast = null;
testobject.loop = testobject;
testobject.dup = test1;
console.log(ObjToSource(testobject));
console.log(testobject.toSource());
Result:
{'run':1,'fast':null,'loop':{},'dup':{'foo':1,'bar':2}}
({run:1, fast:null, loop:{run:1, fast:null, loop:{}, dup:{foo:1, bar:2}}, dup:{foo:1, bar:2}})
NOTE: Trying to print document.body is a terrible example. For one, FF just prints an empty object string when using toSource. And when using the function above, FF crashes on SecurityError: The operation is insecure.. And Chrome will crash on Uncaught RangeError: Maximum call stack size exceeded. Clearly, document.body was not meant to be converted to string. Because its either too large, or against security policy to access certain properties. Unless, I messed something up here, do tell!
If you would like to print the object of its full length, can use
console.log(require('util').inspect(obj, {showHidden: false, depth: null})
If you want to print the object by converting it to the string then
console.log(JSON.stringify(obj));
I needed a way to recursively print the object, which pagewil's answer provided (Thanks!). I updated it a little bit to include a way to print up to a certain level, and to add spacing so that it is properly indented based on the current level that we are in so that it is more readable.
// Recursive print of object
var print = function( o, maxLevel, level ) {
if ( typeof level == "undefined" ) {
level = 0;
}
if ( typeof level == "undefined" ) {
maxLevel = 0;
}
var str = '';
// Remove this if you don't want the pre tag, but make sure to remove
// the close pre tag on the bottom as well
if ( level == 0 ) {
str = '<pre>';
}
var levelStr = '';
for ( var x = 0; x < level; x++ ) {
levelStr += ' ';
}
if ( maxLevel != 0 && level >= maxLevel ) {
str += levelStr + '...</br>';
return str;
}
for ( var p in o ) {
if ( typeof o[p] == 'string' ) {
str += levelStr +
p + ': ' + o[p] + ' </br>';
} else {
str += levelStr +
p + ': { </br>' + print( o[p], maxLevel, level + 1 ) + levelStr + '}</br>';
}
}
// Remove this if you don't want the pre tag, but make sure to remove
// the open pre tag on the top as well
if ( level == 0 ) {
str += '</pre>';
}
return str;
};
Usage:
var pagewilsObject = {
name: 'Wilson Page',
contact: {
email: 'wilson#hotmail.com',
tel: '123456789'
}
}
// Recursive of whole object
$('body').append( print(pagewilsObject) );
// Recursive of myObject up to 1 level, will only show name
// and that there is a contact object
$('body').append( print(pagewilsObject, 1) );
You can also use ES6 template literal concept to display the content of a JavaScript object in a string format.
alert(`${JSON.stringify(obj)}`);
const obj = {
"name" : "John Doe",
"habbits": "Nothing",
};
alert(`${JSON.stringify(obj)}`);
I always use console.log("object will be: ", obj, obj1).
this way I don't need to do the workaround with stringify with JSON.
All the properties of the object will be expanded nicely.
Another way of displaying objects within the console is with JSON.stringify. Checkout the below example:
var gandalf = {
"real name": "Gandalf",
"age (est)": 11000,
"race": "Maia",
"haveRetirementPlan": true,
"aliases": [
"Greyhame",
"Stormcrow",
"Mithrandir",
"Gandalf the Grey",
"Gandalf the White"
]
};
//to console log object, we cannot use console.log("Object gandalf: " + gandalf);
console.log("Object gandalf: ");
//this will show object gandalf ONLY in Google Chrome NOT in IE
console.log(gandalf);
//this will show object gandalf IN ALL BROWSERS!
console.log(JSON.stringify(gandalf));
//this will show object gandalf IN ALL BROWSERS! with beautiful indent
console.log(JSON.stringify(gandalf, null, 4));
Javascript Function
<script type="text/javascript">
function print_r(theObj){
if(theObj.constructor == Array || theObj.constructor == Object){
document.write("<ul>")
for(var p in theObj){
if(theObj[p].constructor == Array || theObj[p].constructor == Object){
document.write("<li>["+p+"] => "+typeof(theObj)+"</li>");
document.write("<ul>")
print_r(theObj[p]);
document.write("</ul>")
} else {
document.write("<li>["+p+"] => "+theObj[p]+"</li>");
}
}
document.write("</ul>")
}
}
</script>
Printing Object
<script type="text/javascript">
print_r(JAVACRIPT_ARRAY_OR_OBJECT);
</script>
via print_r in Javascript
var list = function(object) {
for(var key in object) {
console.log(key);
}
}
where object is your object
or you can use this in chrome dev tools, "console" tab:
console.log(object);
Assume object obj = {0:'John', 1:'Foo', 2:'Bar'}
Print object's content
for (var i in obj){
console.log(obj[i], i);
}
Console output (Chrome DevTools) :
John 0
Foo 1
Bar 2
Hope that helps!
I prefer using console.table for getting clear object format, so imagine you have this object:
const obj = {name: 'Alireza', family: 'Dezfoolian', gender: 'male', netWorth: "$0"};
And you will you see a neat and readable table like this below:
Circular references solution
To make string without redundant information from object which contains duplicate references (references to same object in many places) including circular references, use JSON.stringify with replacer (presented in snippet) as follows
let s = JSON.stringify(obj, refReplacer(), 4);
function refReplacer() {
let m = new Map(), v= new Map(), init = null;
return function(field, value) {
let p= m.get(this) + (Array.isArray(this) ? `[${field}]` : '.' + field);
let isComplex= value===Object(value)
if (isComplex) m.set(value, p);
let pp = v.get(value)||'';
let path = p.replace(/undefined\.\.?/,'');
let val = pp ? `#REF:${pp[0]=='[' ? '$':'$.'}${pp}` : value;
!init ? (init=value) : (val===init ? val="#REF:$" : 0);
if(!pp && isComplex) v.set(value, path);
return val;
}
}
// ---------------
// TEST
// ---------------
// gen obj with duplicate references
let a = { a1: 1, a2: 2 };
let b = { b1: 3, b2: "4" };
let obj = { o1: { o2: a }, b, a }; // duplicate reference
a.a3 = [1,2,b]; // circular reference
b.b3 = a; // circular reference
let s = JSON.stringify(obj, refReplacer(), 4);
console.log(s);
alert(s);
This solution based on this (more info there) create JSONPath like path for each object value and if same object occurs twice (or more) it uses reference with this path to reference that object e.g. #REF:$.bar.arr[3].foo (where $ means main object) instead 'render' whole object (which is less redundant)
BONUS: inversion
function parseRefJSON(json) {
let objToPath = new Map();
let pathToObj = new Map();
let o = JSON.parse(json);
let traverse = (parent, field) => {
let obj = parent;
let path = '#REF:$';
if (field !== undefined) {
obj = parent[field];
path = objToPath.get(parent) + (Array.isArray(parent) ? `[${field}]` : `${field?'.'+field:''}`);
}
objToPath.set(obj, path);
pathToObj.set(path, obj);
let ref = pathToObj.get(obj);
if (ref) parent[field] = ref;
for (let f in obj) if (obj === Object(obj)) traverse(obj, f);
}
traverse(o);
return o;
}
// ------------
// TEST
// ------------
let s = `{
"o1": {
"o2": {
"a1": 1,
"a2": 2,
"a3": [
1,
2,
{
"b1": 3,
"b2": "4",
"b3": "#REF:$.o1.o2"
}
]
}
},
"b": "#REF:$.o1.o2.a3[2]",
"a": "#REF:$.o1.o2"
}`;
console.log('Open Chrome console to see nested fields');
let obj = parseRefJSON(s);
console.log(obj);
A little helper function I always use in my projects for simple, speedy debugging via the console.
Inspiration taken from Laravel.
/**
* #param variable mixed The var to log to the console
* #param varName string Optional, will appear as a label before the var
*/
function dd(variable, varName) {
var varNameOutput;
varName = varName || '';
varNameOutput = varName ? varName + ':' : '';
console.warn(varNameOutput, variable, ' (' + (typeof variable) + ')');
}
Usage
dd(123.55); outputs:
var obj = {field1: 'xyz', field2: 2016};
dd(obj, 'My Cool Obj');
The console.log() does a great job of debugging objects, but if you are looking to print the object to the page content, here's the simplest way that I've come up with to mimic the functionality of PHP's print_r(). A lot these other answers want to reinvent the wheel, but between JavaScript's JSON.stringify() and HTML's <pre> tag, you get exactly what you are looking for.
var obj = { name: 'The Name', contact: { email: 'thename#gmail.com', tel: '123456789' }};
$('body').append('<pre>'+JSON.stringify(obj, null, 4)+'</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
i used pagewil's print method, and it worked very nicely.
here is my slightly extended version with (sloppy) indents and distinct prop/ob delimiters:
var print = function(obj, delp, delo, ind){
delp = delp!=null ? delp : "\t"; // property delimeter
delo = delo!=null ? delo : "\n"; // object delimeter
ind = ind!=null ? ind : " "; // indent; ind+ind geometric addition not great for deep objects
var str='';
for(var prop in obj){
if(typeof obj[prop] == 'string' || typeof obj[prop] == 'number'){
var q = typeof obj[prop] == 'string' ? "" : ""; // make this "'" to quote strings
str += ind + prop + ': ' + q + obj[prop] + q + '; ' + delp;
}else{
str += ind + prop + ': {'+ delp + print(obj[prop],delp,delo,ind+ind) + ind + '}' + delo;
}
}
return str;
};

chrome.i18n.getMessage is always empty

I'm trying to enable i18n to a little chrome extension that I'm working on.
As of now, I only need to translate some strings in the html file. I know that the i18n functionality cannot do that directly, so I wrote my own localization function:
var $objects = $('*[data-message]');
$objects.each(function() {
var $this = $(this);
var messageName = $this.attr('data-message');
var text = $this.html();
var translated = chrome.i18n.getMessage(messageName);
if (translated !== '' && translated !== undefined) {
$this.html(translated);
}
console.log(messageName); // this prints "theTitle"
console.log(translated); // this prints ""
});
This is a string that I have in my html file:
<span data-message="theTitle">Live Quotes Portfolio</span>
And this is my _locales/it/messages.json file:
{
"theTitle": {
"message": "Il titolo",
"description": "The string we search for.."
}
}
The problem is that in the two console logs, the first one prints the correct string that needs to be translated, but the second is always empty.
What am I missing? I also have "default_locale": "it" in my manifest.json...

Is it possible to pass a model to a layout in Express?

I know that it is possible to pass a model to a view in express by doing something like this:
exports.locations = function(req, res){
Location.find(function(err, results) {
res.render('locations', { title: 'Locations', locations: results });
});
};
But is it possible to pass a model to my layout?
Assuming you have all (relevant) routes inside a single .js file, you could add a function like this:
function applyGlobals(pageModel) {
pageModel.myGlobalThing = "I'm always available";
pageModel.anotherGlobalThing = 8675309;
return(pageModel);
}
exports.locations = function(req, res){
Location.find(function(err, results) {
res.render('locations', applyGlobals({ title: 'Locations', locations: results }));
});
};
You could also create a more generalizable solution:
function Globalizer(baseContent) {
var theFunc = function(specificContent) {
var keys = Object.keys(baseContent);
for (var i = 0; i < keys.length; i++)
{
// the lets the page content override global content by not
// overwriting it if it exists;
if(!specificContent.hasOwnProperty(keys[i])){
specificContent[keys[i]] = baseContent[keys[i]];
}
}
return specificContent;
};
return theFunc;
};
// And use it like so.
var applyGlobals = new Globalizer({global1: 12, global2: 'otherthing'});
var pageVars = applyGlobals({item1: 'fifteen', 'item2': 15, global2: 'override'});
console.log(require('util').inspect(pageVars));
Which would emit:
{ item1: 'fifteen',
item2: 15,
global2: 'override',
global1: 12 }
Similarly, you could use one of the various mixin, extend assign or similar functions of various libraries like lodash, underscore, etc. See the doc for lodash.assign() which illustrates accomplishing the same sort of thing.
UPDATE One more way of doing it.
You might want to check out Express' app.locals documentation as well - it might work well for you.

Sharepoint 2010 list creation using ecmascript

i am new to ECMAScript and share point development, i have small requirement i need to create one list using ECMAScript and while creation it has to check whether the list already exists in the site ,if list doesn't exist new list has to create.
You can use SPServices with "GetListCollection" to find all the lists in a Sharepoint, and then use "AddList" to create it.
Something like:
var myList="My List Test"; // the name of your list
var listExists=false;
$().SPServices({
operation: "GetListCollection",
async: true,
webURL:"http://my.share.point/my/dir/",
completefunc: function (xData, Status) {
// go through the result
$(xData.responseXML).find('List').each(function() {
if ($(this).attr("Title") == myList) { listExists=true; return false }
})
// if the list doesn't exist
if (!listExists) {
// see the MSDN documentation available from the SPService website
$().SPServices({
operation: "AddList",
async: true,
webURL:"http://my.share.point/my/dir/",
listName:myList,
description:"My description",
templateID:100
})
}
}
});
Make sure to read the website correctly, and especially the FAQ. You'll need to include jQuery and then SPServices in your code.
You could utilize JSOM or SOAP Services for that purpose, below is demonstrated JSOM solution.
How to create a List using JSOM in SharePoint 2010
function createList(siteUrl,listTitle,listTemplateType,success,error) {
var context = new SP.ClientContext(siteUrl);
var web = context.get_web();
var listCreationInfo = new SP.ListCreationInformation();
listCreationInfo.set_title(listTitle);
listCreationInfo.set_templateType(listTemplateType);
var list = web.get_lists().add(listCreationInfo);
context.load(list);
context.executeQueryAsync(
function(){
success(list);
},
error
);
}
How to determine whether list exists in Web
Unfortunately JSOM API does not contains any "built-in" methods to determine whether list exists or not, but you could use the following approach.
One solution would be to load Web object with lists collection and then iterate through list collection to find a specific list:
context.load(web, 'Lists');
Solution
The following example demonstrates how to determine whether List exist via JSOM:
function listExists(siteUrl,listTitle,success,error) {
var context = new SP.ClientContext(siteUrl);
var web = context.get_web();
context.load(web,'Lists');
context.load(web);
context.executeQueryAsync(
function(){
var lists = web.get_lists();
var listExists = false;
var e = lists.getEnumerator();
while (e.moveNext()) {
var list = e.get_current();
if(list.get_title() == listTitle) {
listExists = true;
break;
}
}
success(listExists);
},
error
);
}
Usage
var webUrl = 'http://contoso.intarnet.com';
var listTitle = 'Toolbox Links';
listExists(webUrl,listTitle,
function(listFound) {
if(!listFound){
createList(webUrl,listTitle,SP.ListTemplateType.links,
function(list){
console.log('List ' + list.get_title() + ' has been created succesfully');
},
function(sender, args) {
console.log('Error:' + args.get_message());
}
);
}
else {
console.log('List with title ' + listTitle + ' already exists');
}
}
);
References
How to: Complete basic operations using JavaScript library code in SharePoint 2013

How to efficiently store/retrieve data to/from chrome.storage.sync?

So, I'm writing an extension to allow people to fine and save colors from images found on the web. It's going well but now I'm trying to conceptualize how I'll actually store them, and list stored items.
As far as I can tell, chrome.storage.sync() only allows for objects. Which means I'd have to do something like this:
{colors: [{colorName: 'white', colorHex: '#ffffff'}, {colorName: 'black', colorHex: '#000000'}]}
Which seems wildly inefficient, since every time I want to add or subtract a color from the favorite list, I will need to get the entire array, change the one item I want, and then store the array back. Not to mention scanning an array for a color to see if it exists or not could be very intensive on a large array.
Ultimately, I'd like to be able to do something along the lines of
colors['#fff'].name = white;
However, that doesn't seem possible.
I'd love to hear some other ideas as to what the best way to accomplish this might be.
The beauty of Javascript is that everything is loosely considered an object. Functions, arrays, and even variables can be accessed as objects.
You could create an array like this,
var colors {}
colors["#FFF"] = "white";
colors["#000"] = "black";
Or perhaps use an array of empty functions,
function color(name, hex /* ... other properties */ ) { }
var colors {
color1: color("white", "#FFF");
color2: color("black", "#000");
}
Then these colors can be accessed by
color1.name
or
color1.hex
Although, because you should use a specific 'key' value for each object in storage, perhaps that is a better way to go.
For instance,
function save_color() {
var white = "#FFF";
//key value callback
chrome.storage.sync.set({"white": white}, function() {
console.log("The value stored was: " + white);
});
}
Or, for multiple colors
function save_colors() {
var white = "#FFF";
var black = "#000";
chrome.storage.sync.set([{"white": white}, {"black": black}], function() {
console.log("The values stored are: " + white + " and " + black);
});
}
I think that may work, i haven't tried storing multiple objects using one api call before, but you should get the point. A good way to implement this may be to have an empty array that gets added to every time the user finds a color they would like to add, then periodically the extension can push the data to sync.
Once you have done a ton of testing and your sync storage is cluttered, keep track of the keys you used during development and remember to run a batch data removal. It would look something like this:
function clear_data() {
var keys = { "white", "black" };
chrome.storage.sync.remove(keys, function() {
for(var i = 0; i < keys.length; i++)
console.log("Removed Data for Key: " + key[i]);
});
}
By the way, to retrieve the value stored in sync,
function load_color() {
var color = "white";
//key callback
chrome.storage.sync.get(color, function(val) {
console.log("The value returned was: " + val);
});
}
I was unsure about this as well, so I made a small example.
manifest.json:
{
"manifest_version": 2,
"name": "Test",
"description": "Test.",
"version": "1.0",
"permissions": [
"storage"
],
"content_scripts": [
{
"matches": ["https://www.google.com/*"],
"js": ["content-script.js"]
}
]
}
content-script.js:
console.log("content script loaded")
function modifyObject() {
chrome.storage.sync.get(null, function(storageData3) {
storageData3.object.property2 = false;
chrome.storage.sync.set(storageData3, function() {
chrome.storage.sync.get(null, function(storageData4) {
console.log("after setting *only* object: " + JSON.stringify(storageData4));
});
});
});
}
// Dumb attempt at setting only property2 of "object"; will add a new top level object "property2".
function attemptToModifyProperty2() {
var toSave = { "property2": false };
chrome.storage.sync.set(toSave, function() {
chrome.storage.sync.get(null, function(storageData2) {
console.log("after attemping to set *only* property2: " + JSON.stringify(storageData2));
modifyObject();
});
});
}
function addArray() {
var toSave = { "array": [1, 2, 3] };
chrome.storage.sync.set(toSave, function() {
chrome.storage.sync.get(null, function(storageData1) {
console.log("after setting *only* array: " + JSON.stringify(storageData1));
attemptToModifyProperty2();
});
});
}
function addObject() {
var toSave = { "object": { "property1": true, "property2": true } };
chrome.storage.sync.set(toSave, function() {
chrome.storage.sync.get(null, function(storageData) {
console.log("after setting *only* object: " + JSON.stringify(storageData));
addArray();
});
});
}
chrome.storage.sync.clear();
addObject();
If you go to google.com (and log in, or change the matches in manifest.json to http), and then open the console, you'll see this output:
content script loaded
content-script.js:42 after setting *only* object: {"object":{"property1":true,"property2":true}}
content-script.js:31 after setting *only* array: {"array":[1,2,3],"object":{"property1":true,"property2":true}}
content-script.js:20 after attemping to set *only* property2: {"array":[1,2,3],"object":{"property1":true,"property2":true},"property2":false}
content-script.js:9 after setting *only* object: {"array":[1,2,3],"object":{"property1":true,"property2":false},"property2":false}
My conclusions from this were that it's only possible to set top-level objects. Even if you want to change only one property that is nested deeply within a top-level object, you will have to pass the entire object to set().

Resources