frg/ftakar-js

View on GitHub
examples/js/ftakar.js

Summary

Maintainability
B
6 hrs
Test Coverage
/**
 * [Created by] Jean Farrugia on 07/03/2015 (dd/mm/yyyy).
 * [Definition] "ftakar" is the equivalent of "remember" in Maltese.
 * 
 * 
 * Copyright (c) 2015 Jean Farrugia
 *
 * Licensed under the MIT License
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 * 
 */
 
(function($) {
    'use strict';

  // https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval#The_.22this.22_problem
  var __nativeSI__ = window.setInterval;
  var setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
    var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2);
    return __nativeSI__(vCallback instanceof Function ? function () {
      vCallback.apply(oThis, aArgs);
    } : vCallback, nDelay);
  };

  $.fn.ftakar = function(options) {
    // default settings
    var settings = $.extend($.fn.ftakar.defaults, options),
    supports_html5_storage = function () {
        // check if browser supports local storage
        try {
            return 'localStorage' in window && window.localStorage !== null;
        } catch (e) {
            // console.info('FTAKAR: html5 storage not supported.');
            return false;
        }
    };

    // check for loacl storage support
    if (supports_html5_storage()) {
        var $this = $(this),
        store = {
            get: function() {
                var a = JSON.parse(localStorage.getItem(settings.savedDataName));
                return (typeof(a) === 'object' && a !== null) ? a : {};
            },
            set: function(data) {
                localStorage.setItem(settings.savedDataName, JSON.stringify(data));
            },
            destroy: function() {
                localStorage.removeItem(settings.savedDataName);
            }
        },
        key = {
            // this key generations stuff can and should be improved
            create: function(element) {
                for (var i = 0; i < settings.idAttribs.length; i++) {
                    // check if attribute has value
                    if ($(element).attr(settings.idAttribs[i]) !== undefined) {
                        // escape strings
                        return encodeURI(settings.idAttribs[i]) + " " + encodeURI($(element).attr( settings.idAttribs[i] ));
                    }
                }

                return false;
            },
            get: function(key) {
                // split
                var array =  key.split(" ");
                for (var index = 0; index < array.length; index++) {
                    // escape strings
                    array[index] = decodeURI(array[index]);
                }
                return array;
            }
        },
        elementData = {
            save: function(element) {
                if (element) {
                    // get data
                    var data = store.get();

                    var elementId = key.create(element);
                    if (elementId) {
                        settings.beforeSave.call();

                        var now = new Date().getTime();
                        var expires = (settings.expireInMs) ? parseInt(now.toString()) + settings.expireInMs : null;

                        var toSave = "";
                        switch ($(element).attr('type')){
                          case 'radio':
                          case 'checkbox':
                            toSave = $(element).prop('checked');
                            break;
                          /*case 'select':
                          case 'input':*/
                          default:
                            toSave = $(element).val();
                        }

                        data[elementId] = {
                                            expires: expires,
                                            val: toSave
                                        };

                        // save data
                        store.set(data);
                        settings.onSave.call();
                        return true;
                    }
                }

                return false;
            },
            destroy: function(element) {
                if (element) {
                    // get data
                    var data = store.get();

                    var elementId = key.create(element);
                    if (elementId) {
                        settings.beforeDelete.call();

                        delete data[elementId];

                        settings.onDelete.call();
                        // save data
                        store.set(data);
                        return true;
                    }
                }

                return false;
            },
            hasExpired: function(data) {
                // check if element has expired
                var now = new Date().getTime();
                return (data.expires) ? (now > data.expires) : false;
            }
        };

        if (settings.clearOnSubmit) {
            // Most of this can be deleted when form domains are implemented
            /*var input = $('input[type=submit]');
            var form = input.length > 0 ? $(input[0].form) : $();*/

            this.closest('form')
                .submit(function(e){
                    e.preventDefault();
                    // when closest form is submitted
                    $this.each(function(){
                        // delete element data
                        elementData.destroy(this);
                    });
            });
        }

        if (settings.saveOnInterval && !isNaN(settings.saveOnInterval) && parseInt(settings.saveOnInterval) > 0) {
          setInterval(
            function(that){
              for (var i = 0; i < that.length; i++) {
                elementData.save(that[i]);
              }
            },
            parseInt(settings.saveOnInterval),
            this
          );
        }

        $(document).ready(function() {
            settings.beforeLoad.call();

            var data = store.get();
            for (var k in data) {
                // loop through saved data
                // check if data has expired
                if (!elementData.hasExpired(data[k])) {
                    // get key
                    var id = key.get(k);
                    // find respective element & set saved data
                    var $element = $('[' + id[0] + '="' + id[1] + '"]');

                    switch ($element.attr('type')){
                      case 'radio':
                      case 'checkbox':
                        $element.prop('checked', data[k].val);
                        break;
                      case 'select':
                        $element.find("option").filter(function() {
                            // may want to use $.trim in here
                            return $(this).text() === data[k].val;
                        }).attr('selected', true);
                        break;
                      default:
                        $element.val(data[k].val);
                    }
                } else {
                    // if data expired.. delete
                    delete data[key];
                }
            }

            // save data.. in case some keys have been deleted
            store.set(data);

            settings.onLoad.call();
        });

        if (settings.saveOnChange) {
          this.change(function(){
              elementData.save(this);
          });
        }
    }

    return this;
  };

  // defaults may be overridden
  $.fn.ftakar.defaults = {
    savedDataName: 'FTAKAR',
    // saveOnInterval: 2000,
    saveOnInterval: false,
    saveOnChange: true,
    clearOnSubmit: true,
    expireInMs: false,
    // priority by order of attribute
    idAttribs: ['id', 'name', 'data-ftakar'],
    beforeSave: function(){ /*console.info('FTAKAR: data is being saved', this);*/ },
    // $(document).trigger( "ftakar__beforeSave" ); // TODO
    onSave: function(){ /*console.info('FTAKAR: data saved', this);*/ },
    // $(document).trigger( "ftakar__onSave" ); // TODO
    beforeLoad: function(){ /*console.info('FTAKAR: data is being loaded');*/ },
    // $(document).trigger( "ftakar__beforeLoad" ); // TODO
    onLoad: function(){ /*console.info('FTAKAR: data has loaded');*/ },
    // $(document).trigger( "ftakar__onLoad" ); // TODO
    beforeDelete: function(){ /*console.info('FTAKAR: element data is going to be deleted', this);*/ },
    // $(document).trigger( "ftakar__beforeDelete" ); // TODO
    onDelete: function(){ /*console.info('FTAKAR: element data deleted', this);*/ },
    // $(document).trigger( "ftakar__onDelete" ); // TODO
    beforeClear: function(){ /*console.info('FTAKAR: data is going to be cleared');*/ },
    // $(document).trigger( "ftakar__beforeClear" ); // TODO
    onClear: function(){ /*console.info('FTAKAR: data cleared');*/ }
    // $(document).trigger( "ftakar__onClear" ); // TODO
  };
}( jQuery ));