📜 ⬆️ ⬇️

Tiny gadget container in 30 lines on pure JS

Having seen on Habrakhabr abrupt implementations of programs in 30 , 24 , 19 and even 1 line, I also decided to blink the clean pages of the habr with something like that. Moreover, for a long time I want to invite an opportunity to work in a new quality for myself.

The fact is that at work I had to learn to write extensions for chromium. Since the task itself was small, it was naturally the first thought that it was natural to write a noodle on the forehead. But having suffered with receiving and storing data in localStorage, I decided that this would not work, and, at least, I had to write some thread wrapper over localStorage.

Generally, at the very beginning I honestly googled for the presence of different frameworks for extensions. Found, for example, Kango . But I did not need cross-browser compatibility (the extension was written only for Chrome), and there was no desire to bother exploring third-party libraries for a small application, so it was decided to write my bicycle.
')
The tasks that were set before the container:

In principle, everything was implemented in a small container, and for small applications it suits me 100%.

So, we have an app object, and it contains only 3 methods: addStorage, addValidator and addModule.

addStorage

Any extension should somewhere store user preferences. OK, we will write

app.addStorage('option'); 

After that, we have a new app.option () method. This method is used to save and retrieve parameters from the option group from localStorage (see the Wishlist # 2: separating flies from cutlets, this group is for user settings only, for other parameters we will create another method). app.option () takes 2 arguments: the name of the parameter and its value. 2nd argument is optional. If it is not specified, the method will return the value of the parameter; if specified, it will save the parameter with that value. app.option under the hood uses JSON.stringify for serialization, and JSON.parse for data extraction.

 app.option('foo', 'bar'); // localStorage['option.foo'] = 'bar' var a = app.option('foo'); // a = 'bar' //      app.option('foo', [1,2,3]); var a = app.option('foo'); // a = [1,2,3] app.option('foo', { bar: [1,2,3] }); var a = app.option('foo'); // a = { bar: [1,2,3] } 

Of course, addStorage is not limited to user settings alone, there we can store any data that needs to be placed in localStorage:

 app.addStorage('whatever_you_want'); app.whatever_you_want('foo', 'bar'); 


addValidator

This method adds a validation rule for a specific parameter. It takes 3 arguments: the name of the group of parameters, the name of the parameter and the actual validating function. This function takes as an argument the value of this parameter and should return the desired value. Each time an app.option ('foo') is called, the validator for foo is called if it is set. For example:

 var a = localStorage['option.foo']; // a = undefined var a = app.option('foo'); // a = undefined app.addValidator('option', 'foo', function(foo) { return typeof foo === 'undefined' ? 'bar' : foo; }); var a = localStorage['option.foo']; // a = undefined var a = app.option('foo'); // a = 'bar' 

This is very convenient in extensions when you first start, since we have no data yet.

addModule

addModule is the most interesting. It allows you to add an entire module to the container. Takes 2 arguments: a name and an object containing methods or properties.

 app.addModule('foo', { bar: function() { // do something... } }); //     bar app.foo.bar(); 

Naturally, if everything were so simple, there would be no point in it. Add a little magic. First, the module object may contain the init () method. Then this method will be called when adding a module (type as a constructor). In it we register any initializing logic for the module. Secondly, the foo module itself becomes a mini-copy of the app container. Those. the addStorage, addValidator, and even addModule functions are available in it! To better demonstrate the work of this approach, let's try to implement a module for localizing the application.

 //         trans() -   app.addModule('i18n', { //      data: {}, //   init: function() { // -    ,    option   i18n, (!)      ,     this.addStorage('option'); //   , ..       this.addValidator('option', 'locale', function(locale) { return typeof locale === 'undefined' ? 'ru' : locale; }); document.write('<script src="/path/to/i18n/' + this.option('locale') + '.js"><\/script>'); this.data = data_from_file; $(document).ready(function() { $('.i18n').each(function() { $(this).text(this.trans($(this).attr('data-i18n'))); }); }); }, trans: function(field) { return typeof this.data[field] === 'undefined' ? field : this.data[field]; } }); 

A little more about this.addStorage('option'); . Here we have created a group of parameters for user settings in the i18n module. It does not coincide with the one we used earlier, it was created in the context of the i18n object. In the application, access to this group is via app.i18n.option('foo'); . All this is again done for Wishlist # 2: we divide the user settings by modules. So it is better to understand what it is.

So, what we got in the end: a clear, clear code structure, nothing dangles in the global scope; the ability to split the application logic into different components; hassle-free work with localStorage - they got what they got, they got it; data validation - once written and forgotten; well, a small container source code - only 30 lines :)

Disclaimer

I do not pretend to any 100% relevance and relevance of this container. Any constructive logic is welcome. I hope someone will find interesting information in this post.

Full text of container code

 var app = { validator: {}, addStorage: function(name) { this[name] = function(key, value) { var local_storage_name = typeof this.name === 'undefined' ? name : this.name + '.' + name; if (typeof value === 'undefined') { var param = typeof localStorage[local_storage_name + '.' + key] !== 'undefined' ? JSON.parse(localStorage[local_storage_name + '.' + key]) : null; if (typeof this.validator[name + '.' + key] !== 'undefined') { param = this.validator[name + '.' + key](param); } return param; } localStorage[local_storage_name + '.' + key] = JSON.stringify(value); }; }, addValidator: function(storage, name, callback) { this.validator[storage + '.' + name] = callback; }, addModule: function(name, object) { object.name = name; object.validator = {}; object.addStorage = this.addStorage; object.addValidator = this.addValidator; object.addModule = this.addModule; this[name] = object; if (typeof this[name].init !== 'undefined') { this[name].init(); } } }; 

Source: https://habr.com/ru/post/203024/


All Articles