var app = angular.module('plunker', []);

app.value('fileSystem', {requestFileSystem: window.requestFileSystem || window.webkitRequestFileSystem});

//default sessionStorage 
app.provider('storageService', function () {
  this.$get = function () {
    return {
      setItem: function (key, value) {
        sessionStorage.setItem(key, value);
        console.log('Fetching newly added key from sessionStorage for verification = ', sessionStorage.getItem(key));
      }
    };
  };  
});

//File System storage if supported. Decorator will take care of it.
app.provider('storageServiceFile', function () {  
  this.$get = ['$window', 'fileSystem', function($window, fileSystem) { 
    var fs;
    function onInitFs(fSys) {
      console.log('Opened file system: ' + fSys.name);
      fs = fSys;
    }
    
    function errorHandler(e) {
      var msg = '';
    
      switch (e.code) {
        case FileError.QUOTA_EXCEEDED_ERR:
          msg = 'QUOTA_EXCEEDED_ERR';
          break;
        case FileError.NOT_FOUND_ERR:
          msg = 'NOT_FOUND_ERR';
          break;
        case FileError.SECURITY_ERR:
          msg = 'SECURITY_ERR';
          break;
        case FileError.INVALID_MODIFICATION_ERR:
          msg = 'INVALID_MODIFICATION_ERR';
          break;
        case FileError.INVALID_STATE_ERR:
          msg = 'INVALID_STATE_ERR';
          break;
        default:
          msg = 'Unknown Error';
          break;
      }
      console.log('Error: ' + msg);
    }
    
    var reqFileSystem = fileSystem.requestFileSystem;
     if (reqFileSystem) {
      reqFileSystem($window.TEMPORARY, 1*1024*1024 /*1MB*/, onInitFs, errorHandler);   
    } 
    return {
      setItem: function (key, value) {
        fs.root.getFile(key, {create: true}, function(fileEntry) {
          // Create a FileWriter object for our FileEntry (log.txt).
          fileEntry.createWriter(function(fileWriter) {
            fileWriter.onwriteend = function(e) {
              console.log('Write completed.');
            };
      
            fileWriter.onerror = function(e) {
              console.log('Write failed: ' + e.toString());
            };
            
            // Create a new Blob and write it to log.txt.
            var blob = new Blob([value], {type: 'text/plain'});
            fileWriter.write(blob);
          }, errorHandler);
        }, errorHandler);
      }
    };
  }];
});

app.config(function($provide) {
  $provide.decorator('storageService', ['$delegate', '$injector', '$rootScope', 'fileSystem', function ($delegate, $injector, $rootScope, fileSystem) {
    if (fileSystem.requestFileSystem) {
      $rootScope.isFileSystemSupported = true;
      return $injector.get('storageServiceFile');
    } else {
     $rootScope.isFileSystemSupported = false;
     return $delegate;
    }
  }]);
});

app.directive('dirResult', ['$rootScope', '$timeout', function ($rootScope, $timeout) {
  function getSessionStorageData() {
    var data = {};
    for (var i = 0; i < sessionStorage.length; i++) {
      var key = sessionStorage.key(i);
      data[key] = sessionStorage[key];
    }    
    return data;
  }
  
  return {
    scope: {},
    controller: function ($scope, $element) {
      $scope.data = getSessionStorageData();
      $rootScope.$on('saveSuccess', function () {
        if ($rootScope.isFileSystemSupported) {//refresh iframe
          var fsIframe = $('iframe[name=fs]')[0];
          $timeout(function () {
            fsIframe.src = fsIframe.src;
          }, 100);
        } else {//refresh data from sessionScope
          $scope.data = getSessionStorageData();
        }
      });
    }
  };
}]);

app.controller('MainCtrl', ['$scope', 'storageService', function($scope, storageService) {
  $scope.record = {};
  $scope.save = function (rec) {
    storageService.setItem(rec.key, rec.value);
    $scope.$emit('saveSuccess');
    toastr.options = {
      "positionClass": "toast-bottom-right",
      "timeOut": 2000
    };
    toastr.success('Data added to storage');
  };
}]);
<!doctype html>
<html ng-app="plunker" >
<head>
  <meta charset="utf-8">
  <title>AngularJS Plunker</title>
  <script>document.write('<base href="' + document.location + '" />');</script>
  <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">
  <link rel="stylesheet" href="style.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script src="https://raw.github.com/CodeSeven/toastr/master/toastr.js"></script>
  <script src="http://code.angularjs.org/1.1.4/angular.js"></script>
  <script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
  <div ng-switch="isFileSystemSupported">
      <h3 ng-switch-when="true">File System API supported by this browser!</h3>
      <h3 ng-switch-when="false">File System API NOT supported by this browser!</h3>
  </div>
  <!--<div class="alert alert-info">
    Verifying the results:
    <ul>
      <li>Browsers that support File System API (only Chrome at the moment. Tested on v26) - Click the following URL <a href="filesystem:http://run.plnkr.co/temporary/" target="_blank">filesystem:http://run.plnkr.co/temporary/</a>. You'll see the list of files added.</li>
      <li>Other browsers that don't support File System API - Watch the console for confirmation message. Data will be added to sessionStorage.</li>
    </ul>
  </div>-->
  <form class="form-inline">
    <fieldset>
      <legend>Enter the data to be stored ...</legend>
      <input type="text" class="input-small" placeholder="Key" ng-model="record.key">
      <input type="text" class="input-small" placeholder="Value" ng-model="record.value">
      <button type="submit" class="btn" ng-click="save(record)">Save</button>
    </fieldset>
  </form>
  <h4>Results</h4>
  <div class="well well-large result" ng-switch="isFileSystemSupported">
    <div ng-switch-when="true" dir-result>
      <iframe name="fs" seamless src="filesystem:http://run.plnkr.co/temporary/" height="200"></iframe>
    </div>
    <div ng-switch-when="false" dir-result>
      <ul>
        <li ng-repeat="(key, value) in data">{{key}} = {{value}}</li>
      </ul>
    </div>
  </div>
</body>
</html> 
/* Put your css in here */
.result ul {
  list-style-type: none;
  padding: 0; 
  margin: 0;
}

.toast-title {
    font-weight: bold;
}

.toast-message {
    -ms-word-wrap: break-word;
    word-wrap: break-word;
}

    .toast-message a,
    .toast-message label {
        color: #FFF;
    }

        .toast-message a:hover {
            color: #CCC;
            text-decoration: none;
        }


.toast-top-full-width {
    top: 0;
    right: 0;
    width: 100%;
}

.toast-bottom-full-width {
    bottom: 0;
    right: 0;
    width: 100%;
}

.toast-top-left {
    top: 12px;
    left: 12px;
}

.toast-top-right {
    top: 12px;
    right: 12px;
}

.toast-bottom-right {
    right: 12px;
    bottom: 12px;
}

.toast-bottom-left {
    bottom: 12px;
    left: 12px;
}

#toast-container {
    position: fixed;
    z-index: 999999;
}

    #toast-container > div {
        margin: 0 0 6px;
        padding: 15px 15px 15px 50px;
        width: 300px;
        -moz-border-radius: 3px 3px 3px 3px;
        -webkit-border-radius: 3px 3px 3px 3px;
        border-radius: 3px 3px 3px 3px;
        background-position: 15px center;
        background-repeat: no-repeat;
        -moz-box-shadow: 0 0 12px #999999;
        -webkit-box-shadow: 0 0 12px #999999;
        box-shadow: 0 0 12px #999999;
        color: #FFFFFF;
        opacity: 0.8;
        -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
        filter: alpha(opacity=80);
    }

.toast {
    background-color: #030303;
}

.toast-success {
    background-color: #51A351;
}

.toast-error {
    background-color: #BD362F;
}

.toast-info {
    background-color: #2F96B4;
}

.toast-warning {
    background-color: #F89406;
}

#toast-container > :hover {
    -moz-box-shadow: 0 0 12px #000000;
    -webkit-box-shadow: 0 0 12px #000000;
    box-shadow: 0 0 12px #000000;
    opacity: 1;
    -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
    filter: alpha(opacity=100);
    cursor: pointer;
}

#toast-container > .toast-info {
    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important;
}

#toast-container > .toast-error {
    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important;
}

#toast-container > .toast-success {
    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important;
}

#toast-container > .toast-warning {
    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important;
}

/*Responsive Design*/

@media all and (max-width: 240px) {
    #toast-container > div {
        padding: 8px 8px 8px 50px;
        width: 108px;
    }
}

@media all and (min-width: 241px) and (max-width: 320px) {
    #toast-container > div {
        padding: 8px 8px 8px 50px;
        width: 128px;
    }
}

@media all and (min-width: 321px) and (max-width: 480px) {
    #toast-container > div {
        padding: 8px 8px 8px 50px;
        width: 192px;
    }
}

@media all and (min-width: 481px) and (max-width: 768px) {
    #toast-container > div {
        padding: 15px 15px 15px 50px;
        width: 300px;
    }
}

/* overrides */
#toast-container.toast-top-full-width > div,
#toast-container.toast-bottom-full-width > div {
    width: 96%;
    margin: 1px auto;
}