<commit_before>angular.module('jumplink.cms.content', [
    'mgcrea.ngStrap',
    'angular-medium-editor',
    'ui.ace',
    'sails.io',
    'jumplink.cms.sortable',
    'ngFocus'
  ])
  .service('ContentService', function ($rootScope, $log, $sailsSocket, $filter, $modal, SortableService, UtilityService, focus) {

    var showHtml = false;
    var editModal = null;

    var getShowHtml = function() {
      return showHtml;
    };

    var setEditModal = function($scope) {
      editModal = $modal({title: 'Inhaltsblock bearbeiten', templateUrl: '/views/modern/contentmodal.jade', show: false});
      editModal.$scope.ok = false;
      editModal.$scope.accept = function (hide) {
        editModal.$scope.ok = true;
        hide();
      };
      editModal.$scope.abort = function (hide) {
        editModal.$scope.ok = false;
        hide();
      };
      editModal.$scope.changeName = false;

      editModal.$scope.$watch('content.title', function(newValue, oldValue) {
        // $log.debug("Content in Content Modal changed!", "new", newValue, "old", oldValue);
        if(editModal.$scope.changeName && angular.isDefined(editModal.$scope.content)) {
          editModal.$scope.content.name = generateName(newValue);
        }
      });

      editModal.$scope.$on('modal.hide.before',function(event, editModal) {
        // $log.debug("edit closed", event, editModal);
        editModal.$scope.changeName = false;
        if(editModal.$scope.ok) {
          return validateContent(editModal.$scope.content, editModal.$scope.callback);
        }
        if(angular.isFunction(editModal.$scope.callback)) {
          return editModal.$scope.callback("discarded", editModal.$scope.content);
        }
      });
      return getEditModal();
    };

    var getEditModal = function() {
      return editModal;
    };

    var subscribe = function() {
      // called on content changes
      $sailsSocket.subscribe('content', function(msg){
        $log.debug("Content event!", msg);
        switch(msg.verb) {
          case 'updated':
            if($rootScope.authenticated) {
              $rootScope.pop('success', 'Seite wurde aktualisiert', msg.id);
            }
          break;
        }
      });
    };

    var toogleShowHtml = function(contents, callback) {
      showHtml = !showHtml;
      if(showHtml && contents) {
        contents = beautifyEach(contents);
      }
      if(angular.isFunction(callback)) {
        return callback(null, showHtml);
      }
      return showHtml;
    };

    var beautify = function(content, callback) {
      content.content = html_beautify(content.content);
      if(angular.isFunction(callback)) {
        return callback(null, content);
      }
      return content;
    };

    var beautifyEach = function(contents, callback) {
      for (var i = contents.length - 1; i >= 0; i--) {
        contents[i].content = beautify(contents[i].content);
      }
      if(angular.isFunction(callback)) {
        return callback(null, contents);
      }
      return contents;
    };

    var getByName = function (contents, name) {
      var index = UtilityService.findKeyValue(contents, 'name', name);
      if(index > -1) {
        return contents[index];
      }
      return null;
    };

    var create = function(data) {
      if(!data || !data.content) {
        data.content = "";
      }
      if(!data || !data.title) {
        data.title = "";
      }
      if(!data || !data.name) {
        data.name = "";
      }
      if(!data || !data.type) {
        data.type = "dynamic";
      }
      if(!data || !data.page) {
        callback("Page not set.");
      }
      return data;
    };

    var append = function(contents, content, callback) {
      SortableService.append(contents, content, callback, true, 'name');
    };

    var createEdit = function(contents, page, callback) {
      var data = create({page:page});
      edit(data, callback, true);
    };

    var swap = function(contents, index_1, index_2, callback) {
      return SortableService.swap(contents, index_1, index_2, callback);
    };

    var moveForward = function(index, contents, callback) {
      return SortableService.moveForward(index, contents, callback);
    };

    var moveBackward = function(index, contents, callback) {
      return SortableService.moveBackward(index, contents, callback);
    };

    var validateContent = function (content, callback) {
      if(content.title) {
        return fix(content, callback);
      }
      if(angular.isFunction(callback)) {
        return callback("Title not set", content);
      }
      return null;
    };

    var edit = function(content, callback, changeName) {
      $log.debug("edit", content);
      editModal.$scope.content = content;
      editModal.$scope.callback = callback;
      if(changeName) {
        editModal.$scope.changeName = changeName;
      }
      else {
        editModal.$scope.changeName = false;
      }
      focus('contentedittitle');
      //- Show when some event occurs (use $promise property to ensure the template has been loaded)
      editModal.$promise.then(editModal.show);
    };

    var removeFromClient = function (contents, index, content, callback) {
      return SortableService.remove(index, contents, callback);
    };

    var remove = function(contents, index, content, page, callback) {
      var errors = [
        'Content konnte nicht gelöscht werden.'
      ];
      if(typeof(index) === 'undefined' || index === null) {
        index = contents.indexOf(content);
      }
      // remove from client
      contents = SortableService.remove(contents, index, content);
      // if content has an id it is saved on database, if not, not
      if(content.id) {
        $log.debug("remove from server, too" ,content);
        $sailsSocket.delete('/content/'+content.id+"?page="+page, {id:content.id, page: page}).success(function(data, status, headers, config) {
          if(angular.isFunction(callback)) {
            return callback(null, contents);
          }
          return contents;
        }).
        error(function(data, status, headers, config) {
          $log.error (errors[0], data);
          if(angular.isFunction(callback)) {
            return callback(data);
          }
          return data;
        });
      } else {
        if(angular.isFunction(callback)) {
          return callback(null, contents);
        }
        return contents;
      }
    };

    var refresh = function(contents, callback) {
      fixEach(contents, function(err, contents) {
        if(err) {
          $log.error(err);
          if(angular.isFunction(callback)) {
            return callback(err);
          }
          return err;
        }
        beautifyEach(contents, function(err, contents) {
          if(err) {
            $log.error(err);
            if(angular.isFunction(callback)) {
              return callback(err);
            }
            return err;
          }
          if(angular.isFunction(callback)) {
            return callback(null, contents);
          }
          return contents;
        });
      });
    };

    var generateName = function (title) {
      var name = "";
      if(title && title !== "") {
        // Set content.name to content.title but only the letters in lower case
        name = title.toLowerCase().replace(/[^a-z1-9]+/g, '');
        $log.debug("set content.name to", name);
      }
      return name;
    };

    /*
     * Validate and fix content to make it saveable
     */
    var fix = function(content, callback) {

      if(angular.isDefined(content)) {
        if(angular.isUndefined(content.name) || content.name === '' || content.name === null) {
          content.name = generateName(content.title);
        }

        if(!content.type || content.type === "") {
          $log.warn("Fix content type not set, set it to dynamic");
          content.type = 'fix';
        }
      } else {
        if(angular.isFunction(callback)) {
          return callback("content not set");
        }
        return null;
      }

      if(angular.isFunction(callback)) {
        return callback(null, content);
      }
      return content;
    };

    /*
     * Validate and fix all contents to make them saveable
     */
    var fixEach = function(contents, callback) {
      for (var i = contents.length - 1; i >= 0; i--) {
        contents[i] = fix(contents[i]);
      }
      if(angular.isFunction(callback)) {
        return callback(null, contents);
      }
      return contents;
    };

    var saveOne = function(content, page, callback) {
      var errors = [
        'Inhalt konnte nicht gespeichert werden'
      ];
      content.page = page;
      fix(content, function(err, content) {
        if(err) {
          if(angular.isFunction(callback)) {
            return callback(err);
          }
          return err;
        }
        $sailsSocket.put('/content/replace', content).success(function(data, status, headers, config) {
          //- $log.debug ("save response from /content/replaceall", data, status, headers, config);
          if(data !== null && typeof(data) !== "undefined") {
            content = data;
            // $log.debug (content);
            if(angular.isFunction(callback)) {
              return callback(null, content);
            }
            return content;
          } else {
            $log.error(errors[0]);
            if(angular.isFunction(callback)) {
              return callback(errors[0]);
            }
            return errors[0];
          }
        }).
        error(function(data, status, headers, config) {
          $log.error (errors[0], data);
          if(angular.isFunction(callback)) {
            return callback(data);
          }
          return data;
        });
      });
    };

    var save = function(contents, page, callback) {
      var errors = [
        'Seite konnte nicht gespeichert werden'
      ];
      fixEach(contents, function(err, contents) {
        if(err) {
          if(angular.isFunction(callback)) {
            return callback(err);
          }
          return err;
        }
        return $sailsSocket.put('/content/replaceall', {contents: contents, page: page}).success(function(data, status, headers, config) {
          //- $log.debug ("save response from /content/replaceall", data, status, headers, config);
          if(data !== null && typeof(data) !== "undefined") {
            contents = $filter('orderBy')(data, 'position');
            // $log.debug (data);
            if(angular.isFunction(callback)) {
              return callback(null, contents);
            }
            return contents;
          }
          $log.error(errors[0]);
          if(angular.isFunction(callback)) {
            return callback(errors[0]);
          }
          return errors[0];
        }).
        error(function(data, status, headers, config) {
          $log.error (errors[0], data);
          if(angular.isFunction(callback)) {
            callback(data);
          }
        });
      });
    };

    var findOne = function(page, name, type, callback, next) {
      var errors = [
        "Error: On trying to find one with page: "+page+", name: "+name,
        "request has more than one results"
      ];
      var query = {
        page: page,
        name: name
      };
      var url = '/content/find';
      if(type) {
        query.type = type;
      }
      return $sailsSocket.put(url, query).then (function (data) {
        if(angular.isUndefined(data) || angular.isUndefined(data.data)) {
          return null;
        }
        if(data.data instanceof Array) {
          data.data = data.data[0];
          $log.error(errors[1]);
        }
        // data.data.content = html_beautify(data.data.content);
        if(next) {
          data.data = next(data.data);
        }
        if(angular.isFunction(callback)) {
          return callback(null, data.data);
        }
        return data.data;
      }, function error (resp){
        $log.error(errors[0], resp);
        if(angular.isFunction(callback)) {
          return callback(errors[0], resp);
        }
        return resp;
      });
    };

    var findAll = function(page, type, callback, next) {
      var errors = [
        "Error: On trying to find all with page: "+page+" and type: "+type,
        "Warn: On trying to find all "+page+" contents! Not found, content is empty!"
      ];
      var query = {
        page: page,
      };
      var url = '/content/findall';
      if(type) {
        query.type = type;
      }
      return $sailsSocket.put(url, query).then (function (data) {
        if(angular.isUndefined(data) || angular.isUndefined(data.data)) {
          $log.warn(errors[1]);
          return null;
        }
        // data.data.content = html_beautify(data.data.content);
        data.data = $filter('orderBy')(data.data, 'position');
        // $log.debug(data);
        if(next) {
          data.data = next(data.data);
        }

        if(angular.isFunction(callback)) {
          callback(null, data.data);
        } else {
          return data.data;
        }
      }, function error (resp){
        $log.error(errors[0], resp);
        if(angular.isFunction(callback)) {
          return callback(errors[0], resp);
        }
        return resp;
      });
    };

    /*
     * get all contents for page including images for each content.name
     */
    var findAllWithImage = function(page, type, callback, next) {
      // $log.debug("findAllWithImage");
      var errors = [
        "Error: On trying to find all with page: "+page+" and type: "+type,
        "Warn: On trying to find all "+page+" contents! Not found, content is empty!"
      ];
      var query = {
        page: page
      };
      var url = '/content/findAllWithImage?page='+page;
      if(type) {
        query.type = type;
        url = url+'&type='+type;
      }
      return $sailsSocket.get(url, query).then (function (data) {
        if(angular.isUndefined(data) || angular.isUndefined(data.data)) {
          $log.warn(errors[1]);
          return null;
        }
        // data.data.content = html_beautify(data.data.content);
        data.data.contents = $filter('orderBy')(data.data.contents, 'position');
        data.data.images = $filter('orderBy')(data.data.images, 'position');
        // $log.debug(data);
        if(next) {
          data.data = next(data.data);
        }
        if(angular.isFunction(callback)) {
          return callback(null, data.data);
        }
        return data.data;
      }, function error (resp){
        $log.error(errors[0], resp);
        if(angular.isFunction(callback)) {
          return callback(errors[0], resp);
        }
        return resp;
      });
    };

    /**
     * Resolve function for angular ui-router.
     * name, callback and next parameters are optional.
     * use next to transform the result before you get it back
     * use callback if you want not use promise
     */
    var find = function(page, name, type, callback, next) {
      //- get soecial content (one)
      if(angular.isDefined(name)) {
        return findOne(page, name, type, next);
      // get all for page
      } else {
        return findAll(page, type, callback, next);
      }
    };

    return {
      subscribe: subscribe,
      setEditModal: setEditModal,
      getShowHtml: getShowHtml,
      toogleShowHtml: toogleShowHtml,
      beautify: beautify,
      beautifyEach: beautifyEach,
      create: create,
      createEdit: createEdit,
      append: append,
      swap: swap,
      moveForward: moveForward,
      moveBackward: moveBackward,
      edit: edit,
      removeFromClient: removeFromClient,
      remove: remove,
      refresh: refresh,
      fix: fix,
      fixEach: fixEach,
      save: save,
      saveOne: saveOne,
      find: find,
      resolve: find, // alias
      findOne: findOne,
      resolveOne: findOne, // alias
      findAll: findAll,
      resolveAll: findAll, //alias
      findAllWithImage: findAllWithImage,
      resolveAllWithImage: findAllWithImage,  //alias
      getByName: getByName
    };
  })
;<commit_msg>fix position if not set<commit_after>angular.module('jumplink.cms.content', [
    'mgcrea.ngStrap',
    'angular-medium-editor',
    'ui.ace',
    'sails.io',
    'jumplink.cms.sortable',
    'ngFocus'
  ])
  .service('ContentService', function ($rootScope, $log, $sailsSocket, $filter, $modal, SortableService, UtilityService, focus) {

    var showHtml = false;
    var editModal = null;

    var getShowHtml = function() {
      return showHtml;
    };

    var setEditModal = function($scope) {
      editModal = $modal({title: 'Inhaltsblock bearbeiten', templateUrl: '/views/modern/contentmodal.jade', show: false});
      editModal.$scope.ok = false;
      editModal.$scope.accept = function (hide) {
        editModal.$scope.ok = true;
        hide();
      };
      editModal.$scope.abort = function (hide) {
        editModal.$scope.ok = false;
        hide();
      };
      editModal.$scope.changeName = false;

      editModal.$scope.$watch('content.title', function(newValue, oldValue) {
        // $log.debug("Content in Content Modal changed!", "new", newValue, "old", oldValue);
        if(editModal.$scope.changeName && angular.isDefined(editModal.$scope.content)) {
          editModal.$scope.content.name = generateName(newValue);
        }
      });

      editModal.$scope.$on('modal.hide.before',function(event, editModal) {
        // $log.debug("edit closed", event, editModal);
        editModal.$scope.changeName = false;
        if(editModal.$scope.ok) {
          return validateContent(editModal.$scope.content, editModal.$scope.callback);
        }
        if(angular.isFunction(editModal.$scope.callback)) {
          return editModal.$scope.callback("discarded", editModal.$scope.content);
        }
      });
      return getEditModal();
    };

    var getEditModal = function() {
      return editModal;
    };

    var subscribe = function() {
      // called on content changes
      $sailsSocket.subscribe('content', function(msg){
        $log.debug("Content event!", msg);
        switch(msg.verb) {
          case 'updated':
            if($rootScope.authenticated) {
              $rootScope.pop('success', 'Seite wurde aktualisiert', msg.id);
            }
          break;
        }
      });
    };

    var toogleShowHtml = function(contents, callback) {
      showHtml = !showHtml;
      if(showHtml && contents) {
        contents = beautifyEach(contents);
      }
      if(angular.isFunction(callback)) {
        return callback(null, showHtml);
      }
      return showHtml;
    };

    var beautify = function(content, callback) {
      content.content = html_beautify(content.content);
      if(angular.isFunction(callback)) {
        return callback(null, content);
      }
      return content;
    };

    var beautifyEach = function(contents, callback) {
      for (var i = contents.length - 1; i >= 0; i--) {
        contents[i].content = beautify(contents[i].content);
      }
      if(angular.isFunction(callback)) {
        return callback(null, contents);
      }
      return contents;
    };

    var getByName = function (contents, name) {
      var index = UtilityService.findKeyValue(contents, 'name', name);
      if(index > -1) {
        return contents[index];
      }
      return null;
    };

    var create = function(data) {
      if(!data || !data.content) {
        data.content = "";
      }
      if(!data || !data.title) {
        data.title = "";
      }
      if(!data || !data.name) {
        data.name = "";
      }
      if(!data || !data.type) {
        data.type = "dynamic";
      }
      if(!data || !data.page) {
        callback("Page not set.");
      }
      return data;
    };

    var append = function(contents, content, callback) {
      SortableService.append(contents, content, callback, true, 'name');
    };

    var createEdit = function(contents, page, callback) {
      var data = create({page:page});
      edit(data, callback, true);
    };

    var swap = function(contents, index_1, index_2, callback) {
      return SortableService.swap(contents, index_1, index_2, callback);
    };

    var moveForward = function(index, contents, callback) {
      return SortableService.moveForward(index, contents, callback);
    };

    var moveBackward = function(index, contents, callback) {
      return SortableService.moveBackward(index, contents, callback);
    };

    var validateContent = function (content, callback) {
      if(content.title) {
        return fix(content, callback);
      }
      if(angular.isFunction(callback)) {
        return callback("Title not set", content);
      }
      return null;
    };

    var edit = function(content, callback, changeName) {
      $log.debug("edit", content);
      editModal.$scope.content = content;
      editModal.$scope.callback = callback;
      if(changeName) {
        editModal.$scope.changeName = changeName;
      }
      else {
        editModal.$scope.changeName = false;
      }
      focus('contentedittitle');
      //- Show when some event occurs (use $promise property to ensure the template has been loaded)
      editModal.$promise.then(editModal.show);
    };

    var removeFromClient = function (contents, index, content, callback) {
      return SortableService.remove(index, contents, callback);
    };

    var remove = function(contents, index, content, page, callback) {
      var errors = [
        'Content konnte nicht gelöscht werden.'
      ];
      if(typeof(index) === 'undefined' || index === null) {
        index = contents.indexOf(content);
      }
      // remove from client
      contents = SortableService.remove(contents, index, content);
      // if content has an id it is saved on database, if not, not
      if(content.id) {
        $log.debug("remove from server, too" ,content);
        $sailsSocket.delete('/content/'+content.id+"?page="+page, {id:content.id, page: page}).success(function(data, status, headers, config) {
          if(angular.isFunction(callback)) {
            return callback(null, contents);
          }
          return contents;
        }).
        error(function(data, status, headers, config) {
          $log.error (errors[0], data);
          if(angular.isFunction(callback)) {
            return callback(data);
          }
          return data;
        });
      } else {
        if(angular.isFunction(callback)) {
          return callback(null, contents);
        }
        return contents;
      }
    };

    var refresh = function(contents, callback) {
      fixEach(contents, function(err, contents) {
        if(err) {
          $log.error(err);
          if(angular.isFunction(callback)) {
            return callback(err);
          }
          return err;
        }
        beautifyEach(contents, function(err, contents) {
          if(err) {
            $log.error(err);
            if(angular.isFunction(callback)) {
              return callback(err);
            }
            return err;
          }
          if(angular.isFunction(callback)) {
            return callback(null, contents);
          }
          return contents;
        });
      });
    };

    var generateName = function (title) {
      var name = "";
      if(title && title !== "") {
        // Set content.name to content.title but only the letters in lower case
        name = title.toLowerCase().replace(/[^a-z1-9]+/g, '');
        $log.debug("set content.name to", name);
      }
      return name;
    };

    /*
     * Validate and fix content to make it saveable
     */
    var fix = function(content, callback) {

      if(angular.isDefined(content)) {
        if(angular.isUndefined(content.name) || content.name === '' || content.name === null) {
          content.name = generateName(content.title);
        }

        if(!angular.isNumber(content.position)) {
          content.position = 0;
        }

        if(!content.type || content.type === "") {
          $log.warn("Fix content type not set, set it to dynamic");
          content.type = 'fix';
        }
      } else {
        if(angular.isFunction(callback)) {
          return callback("content not set");
        }
        return null;
      }

      if(angular.isFunction(callback)) {
        return callback(null, content);
      }
      return content;
    };

    /*
     * Validate and fix all contents to make them saveable
     */
    var fixEach = function(contents, callback) {
      for (var i = contents.length - 1; i >= 0; i--) {
        contents[i] = fix(contents[i]);
      }
      if(angular.isFunction(callback)) {
        return callback(null, contents);
      }
      return contents;
    };

    var saveOne = function(content, page, callback) {
      var errors = [
        'Inhalt konnte nicht gespeichert werden'
      ];
      content.page = page;
      fix(content, function(err, content) {
        if(err) {
          if(angular.isFunction(callback)) {
            return callback(err);
          }
          return err;
        }
        $sailsSocket.put('/content/replace', content).success(function(data, status, headers, config) {
          //- $log.debug ("save response from /content/replaceall", data, status, headers, config);
          if(data !== null && typeof(data) !== "undefined") {
            content = data;
            // $log.debug (content);
            if(angular.isFunction(callback)) {
              return callback(null, content);
            }
            return content;
          } else {
            $log.error(errors[0]);
            if(angular.isFunction(callback)) {
              return callback(errors[0]);
            }
            return errors[0];
          }
        }).
        error(function(data, status, headers, config) {
          $log.error (errors[0], data);
          if(angular.isFunction(callback)) {
            return callback(data);
          }
          return data;
        });
      });
    };

    var save = function(contents, page, callback) {
      var errors = [
        'Seite konnte nicht gespeichert werden'
      ];
      fixEach(contents, function(err, contents) {
        if(err) {
          if(angular.isFunction(callback)) {
            return callback(err);
          }
          return err;
        }
        return $sailsSocket.put('/content/replaceall', {contents: contents, page: page}).success(function(data, status, headers, config) {
          //- $log.debug ("save response from /content/replaceall", data, status, headers, config);
          if(data !== null && typeof(data) !== "undefined") {
            contents = $filter('orderBy')(data, 'position');
            // $log.debug (data);
            if(angular.isFunction(callback)) {
              return callback(null, contents);
            }
            return contents;
          }
          $log.error(errors[0]);
          if(angular.isFunction(callback)) {
            return callback(errors[0]);
          }
          return errors[0];
        }).
        error(function(data, status, headers, config) {
          $log.error (errors[0], data);
          if(angular.isFunction(callback)) {
            callback(data);
          }
        });
      });
    };

    var findOne = function(page, name, type, callback, next) {
      var errors = [
        "Error: On trying to find one with page: "+page+", name: "+name,
        "request has more than one results"
      ];
      var query = {
        page: page,
        name: name
      };
      var url = '/content/find';
      if(type) {
        query.type = type;
      }
      return $sailsSocket.put(url, query).then (function (data) {
        if(angular.isUndefined(data) || angular.isUndefined(data.data)) {
          return null;
        }
        if(data.data instanceof Array) {
          data.data = data.data[0];
          $log.error(errors[1]);
        }
        // data.data.content = html_beautify(data.data.content);
        if(next) {
          data.data = next(data.data);
        }
        if(angular.isFunction(callback)) {
          return callback(null, data.data);
        }
        return data.data;
      }, function error (resp){
        $log.error(errors[0], resp);
        if(angular.isFunction(callback)) {
          return callback(errors[0], resp);
        }
        return resp;
      });
    };

    var findAll = function(page, type, callback, next) {
      var errors = [
        "Error: On trying to find all with page: "+page+" and type: "+type,
        "Warn: On trying to find all "+page+" contents! Not found, content is empty!"
      ];
      var query = {
        page: page,
      };
      var url = '/content/findall';
      if(type) {
        query.type = type;
      }
      return $sailsSocket.put(url, query).then (function (data) {
        if(angular.isUndefined(data) || angular.isUndefined(data.data)) {
          $log.warn(errors[1]);
          return null;
        }
        // data.data.content = html_beautify(data.data.content);
        data.data = $filter('orderBy')(data.data, 'position');
        // $log.debug(data);
        if(next) {
          data.data = next(data.data);
        }

        if(angular.isFunction(callback)) {
          callback(null, data.data);
        } else {
          return data.data;
        }
      }, function error (resp){
        $log.error(errors[0], resp);
        if(angular.isFunction(callback)) {
          return callback(errors[0], resp);
        }
        return resp;
      });
    };

    /*
     * get all contents for page including images for each content.name
     */
    var findAllWithImage = function(page, type, callback, next) {
      // $log.debug("findAllWithImage");
      var errors = [
        "Error: On trying to find all with page: "+page+" and type: "+type,
        "Warn: On trying to find all "+page+" contents! Not found, content is empty!"
      ];
      var query = {
        page: page
      };
      var url = '/content/findAllWithImage?page='+page;
      if(type) {
        query.type = type;
        url = url+'&type='+type;
      }
      return $sailsSocket.get(url, query).then (function (data) {
        if(angular.isUndefined(data) || angular.isUndefined(data.data)) {
          $log.warn(errors[1]);
          return null;
        }
        // data.data.content = html_beautify(data.data.content);
        data.data.contents = $filter('orderBy')(data.data.contents, 'position');
        data.data.images = $filter('orderBy')(data.data.images, 'position');
        // $log.debug(data);
        if(next) {
          data.data = next(data.data);
        }
        if(angular.isFunction(callback)) {
          return callback(null, data.data);
        }
        return data.data;
      }, function error (resp){
        $log.error(errors[0], resp);
        if(angular.isFunction(callback)) {
          return callback(errors[0], resp);
        }
        return resp;
      });
    };

    /**
     * Resolve function for angular ui-router.
     * name, callback and next parameters are optional.
     * use next to transform the result before you get it back
     * use callback if you want not use promise
     */
    var find = function(page, name, type, callback, next) {
      //- get soecial content (one)
      if(angular.isDefined(name)) {
        return findOne(page, name, type, next);
      // get all for page
      } else {
        return findAll(page, type, callback, next);
      }
    };

    return {
      subscribe: subscribe,
      setEditModal: setEditModal,
      getShowHtml: getShowHtml,
      toogleShowHtml: toogleShowHtml,
      beautify: beautify,
      beautifyEach: beautifyEach,
      create: create,
      createEdit: createEdit,
      append: append,
      swap: swap,
      moveForward: moveForward,
      moveBackward: moveBackward,
      edit: edit,
      removeFromClient: removeFromClient,
      remove: remove,
      refresh: refresh,
      fix: fix,
      fixEach: fixEach,
      save: save,
      saveOne: saveOne,
      find: find,
      resolve: find, // alias
      findOne: findOne,
      resolveOne: findOne, // alias
      findAll: findAll,
      resolveAll: findAll, //alias
      findAllWithImage: findAllWithImage,
      resolveAllWithImage: findAllWithImage,  //alias
      getByName: getByName
    };
  })
;<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import c from 'classnames';
import FlatButton from 'material-ui/FlatButton';
import {Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui/Table';
import {range} from 'ramda';
import {Link} from 'react-router';
import {get} from 'lodash';
import {hashHistory} from 'react-router';

import TopBar from './../../components/TopBar/TopBar';
import Breadcrumb from './../Breadcrumb/Breadcrumb';
import {setSnackBarParams} from './../../redux/modules/ui';
import {getFolder} from './../../redux/modules/folder';
import {listFolderEntries, setSelectedFolderEntryIds, clearSelectedFolderEntryIds,
  deleteEntries} from './../../redux/modules/entry';

import injectF from './../../helpers/injectF';
import injectPush from './../../helpers/injectPush';
import resolve from './../../helpers/resolve';
import Pagination from './../../components/Pagination/Pagination';
import SearchBar from './../../components/SearchBar/SearchBar';
import hasValue from './../../helpers/hasValue';
import getFontSize from './../../helpers/getFontSize';
import SEARCH_TYPES from './../../constants/searchTypes';

const styles = require('./PageEntries.scss');

@connect(({main, folder, entry}) => ({
  perpage: entry.get('perpage'),
  folder: folder.get('folder'),
  importingFolderId: folder.get('importingFolderId'),
  interfaceFontSizeScalingFactor: main.get('interfaceFontSizeScalingFactor'),
  folderEntries: entry.get('folderEntries'),
  folderEntryCount: entry.get('folderEntryCount'),
  selectedFolderEntryMap: entry.get('selectedFolderEntryMap')
}), {listFolderEntries, setSnackBarParams, setSelectedFolderEntryIds,
  deleteEntries, clearSelectedFolderEntryIds})
@injectPush
@injectF
@resolve(({dispatch}, {params, page, perpage}) => {

  const promises = [];
  promises.push(dispatch(getFolder({id: params.id})));
  promises.push(dispatch(listFolderEntries({folderId: params.id, page, perpage})));
  promises.push(dispatch(setSelectedFolderEntryIds([])));

  return Promise.all(promises);
})
export default class PageEntries extends Component {

  static propTypes = {
    push: PropTypes.func.isRequired,
    perpage: PropTypes.number.isRequired,
    f: PropTypes.func.isRequired,
    folder: PropTypes.object.isRequired,
    folderEntries: PropTypes.array.isRequired,
    interfaceFontSizeScalingFactor: PropTypes.number.isRequired,
    folderEntryCount: PropTypes.number.isRequired,
    params: PropTypes.object.isRequired,
    listFolderEntries: PropTypes.func.isRequired,
    setSelectedFolderEntryIds: PropTypes.func.isRequired,
    clearSelectedFolderEntryIds: PropTypes.func.isRequired,
    selectedFolderEntryMap: PropTypes.object.isRequired,
    deleteEntries: PropTypes.func.isRequired,
    importingFolderId: PropTypes.number,
    setSnackBarParams: PropTypes.func.isRequired
  };

  constructor(props) {
    super(props);
    this.state = {
      page: 1,
      tableKey: 0,
      searchKeyword: '',
      searchType: 'source-entry'
    };
  }

  componentWillUpdate(nextProps, nextState) {
    const {page, searchKeyword, searchType} = this.state;
    const {perpage, listFolderEntries} = this.props;

    if ((page !== nextState.page) || (perpage !== nextProps.perpage) ||
        (searchKeyword !== nextState.searchKeyword) || (searchType !== nextState.searchType)) {

      listFolderEntries({
        folderId: nextProps.folder.id,
        page: nextState.page,
        perpage: nextProps.perpage,
        keyword: nextState.searchKeyword.trim(),
        type: nextState.searchType
      });
    }
  }

  handleRowSelection = (res) => {

    const {setSelectedFolderEntryIds, perpage, folderEntries} = this.props;

    let indices = res;

    if ('all' === res) {
      indices = range(0, perpage);
    }
    else if ('none' === res) {
      indices = [];
    }

    const ids = folderEntries.filter((row, index) => (-1 !== indices.indexOf(index)))
      .map((row) => row.id);

    setSelectedFolderEntryIds(ids);
  };

  goToSingleFolderEntryPage = (entryId) => {
    const {folder, push} = this.props;
    return () => push(`/folders/${folder.id}/entries/${entryId}`);
  };

  renderFolderEntries() {

    const fontSize = 20;
    const colStyle = {fontSize, width: 'initial'};
    const {tableKey} = this.state;
    const {folderEntries, f} = this.props;

    const tableRows = folderEntries.map((entry) => {
      return (
        <TableRow key={`table-row-${entry.id}`}>
          <TableRowColumn style={colStyle}>
            {entry.sourceEntry}
          </TableRowColumn>
          <TableRowColumn style={colStyle}>{get(entry, 'data.page-num', '')}</TableRowColumn>
        </TableRow>
      );
    });

    // https://github.com/callemall/material-ui/issues/6006#issuecomment-277669719
    const key = `table-workaround-${tableKey}`;

    return (

        <TableHeader>
          <TableRow>
            <TableHeaderColumn style={colStyle}>{f('source-entry')}</TableHeaderColumn>
            <TableHeaderColumn style={colStyle}>{f('page-num')}</TableHeaderColumn>
          </TableRow>
        </TableHeader>
        <TableBody showRowHover deselectOnClickaway={false}>{tableRows}</TableBody>

    );
  }

  goToAddFolderEntryPage = () => {
    const {folder, push} = this.props;
    push(`/folders/${folder.id}/entries/add`);
  };

  updateTableKey = () => this.setState((prevState) => ({tableKey: prevState.tableKey + 1}));

  deleteSelectedFolderEntries = async () => {

    const {page} = this.state;
    const {selectedFolderEntryMap, f, deleteEntries, perpage, params, listFolderEntries,
      setSnackBarParams, folderEntryCount, clearSelectedFolderEntryIds} = this.props;

    const ids = Object.keys(selectedFolderEntryMap);
    await deleteEntries({ids});
    clearSelectedFolderEntryIds();
    const totalPages = Math.ceil((folderEntryCount - ids.length) / perpage);
    const nextPage = (page > totalPages) ? totalPages : page;

    await listFolderEntries({folderId: params.id, page: nextPage, perpage});
    this.setState({page: nextPage});
    setSnackBarParams(true, f('folder-entries-has-been-deleted', {count: ids.length}));
    this.updateTableKey();
  };

  renderDeleteButton() {
    const {selectedFolderEntryMap, f} = this.props;
    if (Object.keys(selectedFolderEntryMap).length > 0) {
      return <FlatButton label={f('delete')} icon={} onTouchTap={this.deleteSelectedFolderEntries} />;
    }
  }

  handlePageButtonTouchTap = (page) => {
    this.updateTableKey();
    this.setState({page});
  };

  handleSearchInputChange = (searchKeyword) => {
    if (this.state.searchKeyword !== searchKeyword) {
      this.setState({page: 1});
    }
    this.setState({searchKeyword});
  };

  handleSearchTypeChange = (event, key, searchType) => this.setState({searchType});

  getMatchedCount() {

    const {searchKeyword} = this.state;
    const {folderEntryCount} = this.props;

    if (hasValue(searchKeyword)) {
      return folderEntryCount;
    }
    return 0;
  }

  handleClearSearchButtonTouchTap = () => {
    this.setState({searchKeyword: ''});
    this.refs.searchBar.getWrappedInstance().getWrappedInstance().clear();
  };

  isImporting() {
    const {folder, importingFolderId} = this.props;
    return folder.id === importingFolderId;
  }

  render() {

    const {page, searchType, searchKeyword} = this.state;
    const {f, folder, folderEntryCount, perpage, interfaceFontSizeScalingFactor} = this.props;
    const matchedCount = this.getMatchedCount();
    const buttonFontSize = getFontSize(interfaceFontSizeScalingFactor, 0.9);

    return (

        <TopBar>
          <Breadcrumb>
            <Link to="/">{f('folders')}</Link>
            {f('folder-entries', {folderName: folder.name})}
          </Breadcrumb>

            {this.renderDeleteButton()}
            <FlatButton icon={} labelStyle={{fontSize: buttonFontSize}}
              label={f('add-entry')} onTouchTap={this.goToAddFolderEntryPage} disabled={this.isImporting()} />
            <FlatButton icon={} labelStyle={{fontSize: buttonFontSize}}
              label={f('back')} onTouchTap={hashHistory.goBack} />

        </TopBar>

          <SearchBar ref="searchBar" onInputChange={this.handleSearchInputChange} searchTypes={SEARCH_TYPES}
            searchKeyword={searchKeyword} matchedCount={matchedCount}
            selectedSearchType={searchType} onSearchTypeChange={this.handleSearchTypeChange}
            onClearFilterButtonTouchTap={this.handleClearSearchButtonTouchTap} />
          {this.renderFolderEntries()}
          {(folderEntryCount > perpage) && <Pagination current={page} total={Math.ceil(folderEntryCount / perpage)}
            onButtonTouchTap={this.handlePageButtonTouchTap} />}

    );
  }
}
<commit_msg>add function setPageEntriesParams to cache duck<commit_after>import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import c from 'classnames';
import FlatButton from 'material-ui/FlatButton';
import {Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui/Table';
import {range} from 'ramda';
import {Link} from 'react-router';
import {get} from 'lodash';
import {hashHistory} from 'react-router';

import TopBar from './../../components/TopBar/TopBar';
import Breadcrumb from './../Breadcrumb/Breadcrumb';
import {setSnackBarParams} from './../../redux/modules/ui';
import {getFolder} from './../../redux/modules/folder';
import {listFolderEntries, setSelectedFolderEntryIds, clearSelectedFolderEntryIds,
  deleteEntries} from './../../redux/modules/entry';
import {setPageEntriesParams} from './../../redux/modules/cache';

import injectF from './../../helpers/injectF';
import injectPush from './../../helpers/injectPush';
import resolve from './../../helpers/resolve';
import Pagination from './../../components/Pagination/Pagination';
import SearchBar from './../../components/SearchBar/SearchBar';
import hasValue from './../../helpers/hasValue';
import getFontSize from './../../helpers/getFontSize';
import SEARCH_TYPES from './../../constants/searchTypes';

const styles = require('./PageEntries.scss');

@connect(({main, folder, entry, cache}) => ({
  cacheDataSet: cache.get('cachePageEntriesDataSet'),
  perpage: entry.get('perpage'),
  folder: folder.get('folder'),
  importingFolderId: folder.get('importingFolderId'),
  interfaceFontSizeScalingFactor: main.get('interfaceFontSizeScalingFactor'),
  folderEntries: entry.get('folderEntries'),
  folderEntryCount: entry.get('folderEntryCount'),
  selectedFolderEntryMap: entry.get('selectedFolderEntryMap')
}), {listFolderEntries, setSnackBarParams, setSelectedFolderEntryIds, setPageEntriesParams,
  deleteEntries, clearSelectedFolderEntryIds})
@injectPush
@injectF
@resolve(({dispatch}, {params, page, perpage, cacheDataSet}) => {

  const promises = [];
  promises.push(dispatch(getFolder({id: params.id})));
  promises.push(dispatch(setSelectedFolderEntryIds([])));

  const folderId = params.id;
  const cacheData = cacheDataSet[folderId] || {};

  const searchParams = Object.assign({
    folderId,
    page,
    perpage
  }, cacheData);
  console.log('searchParams', searchParams);
  promises.push(dispatch(listFolderEntries(searchParams)));

  return Promise.all(promises);
})
export default class PageEntries extends Component {

  static propTypes = {
    cacheDataSet: PropTypes.object.isRequired,
    push: PropTypes.func.isRequired,
    perpage: PropTypes.number.isRequired,
    f: PropTypes.func.isRequired,
    folder: PropTypes.object.isRequired,
    folderEntries: PropTypes.array.isRequired,
    interfaceFontSizeScalingFactor: PropTypes.number.isRequired,
    folderEntryCount: PropTypes.number.isRequired,
    params: PropTypes.object.isRequired,
    listFolderEntries: PropTypes.func.isRequired,
    setPageEntriesParams: PropTypes.func.isRequired,
    setSelectedFolderEntryIds: PropTypes.func.isRequired,
    clearSelectedFolderEntryIds: PropTypes.func.isRequired,
    selectedFolderEntryMap: PropTypes.object.isRequired,
    deleteEntries: PropTypes.func.isRequired,
    importingFolderId: PropTypes.number,
    setSnackBarParams: PropTypes.func.isRequired
  };

  constructor(props) {
    super(props);
    const cacheData = props.cacheDataSet[props.folder.id] || {};
    this.state = Object.assign({
      page: 1,
      tableKey: 0,
      searchKeyword: '',
      searchType: 'source-entry'
    }, cacheData);
    console.log('init state', this.state);
  }

  componentWillUpdate(nextProps, nextState) {
    const {page, searchKeyword, searchType} = this.state;
    const {perpage, listFolderEntries, setPageEntriesParams} = this.props;
    const nextPage = nextState.page;
    const nextPerpage = nextProps.perpage;
    const nextSearchKeyword = nextState.searchKeyword;
    const nextSearchType = nextState.searchType;
    const folderId = nextProps.folder.id;

    if ((page !== nextPage) || (perpage !== nextPerpage) ||
        (searchKeyword !== nextSearchKeyword) || (searchType !== nextSearchType)) {

      setPageEntriesParams(folderId, {
        page: nextPage,
        searchKeyword: nextSearchKeyword,
        searchType: nextSearchType
      });

      listFolderEntries({
        folderId,
        page: nextPage,
        perpage: nextPerpage,
        searchKeyword: nextSearchKeyword.trim(),
        searchType: nextSearchType
      });
    }
  }

  handleRowSelection = (res) => {

    const {setSelectedFolderEntryIds, perpage, folderEntries} = this.props;

    let indices = res;

    if ('all' === res) {
      indices = range(0, perpage);
    }
    else if ('none' === res) {
      indices = [];
    }

    const ids = folderEntries.filter((row, index) => (-1 !== indices.indexOf(index)))
      .map((row) => row.id);

    setSelectedFolderEntryIds(ids);
  };

  goToSingleFolderEntryPage = (entryId) => {
    const {folder, push} = this.props;
    return () => push(`/folders/${folder.id}/entries/${entryId}`);
  };

  renderFolderEntries() {

    const fontSize = 20;
    const colStyle = {fontSize, width: 'initial'};
    const {tableKey} = this.state;
    const {folderEntries, f} = this.props;

    const tableRows = folderEntries.map((entry) => {
      return (
        <TableRow key={`table-row-${entry.id}`}>
          <TableRowColumn style={colStyle}>
            {entry.sourceEntry}
          </TableRowColumn>
          <TableRowColumn style={colStyle}>{get(entry, 'data.page-num', '')}</TableRowColumn>
        </TableRow>
      );
    });

    // https://github.com/callemall/material-ui/issues/6006#issuecomment-277669719
    const key = `table-workaround-${tableKey}`;

    return (

        <TableHeader>
          <TableRow>
            <TableHeaderColumn style={colStyle}>{f('source-entry')}</TableHeaderColumn>
            <TableHeaderColumn style={colStyle}>{f('page-num')}</TableHeaderColumn>
          </TableRow>
        </TableHeader>
        <TableBody showRowHover deselectOnClickaway={false}>{tableRows}</TableBody>

    );
  }

  goToAddFolderEntryPage = () => {
    const {folder, push} = this.props;
    push(`/folders/${folder.id}/entries/add`);
  };

  updateTableKey = () => this.setState((prevState) => ({tableKey: prevState.tableKey + 1}));

  deleteSelectedFolderEntries = async () => {

    const {page} = this.state;
    const {selectedFolderEntryMap, f, deleteEntries, perpage, params, listFolderEntries,
      setSnackBarParams, folderEntryCount, clearSelectedFolderEntryIds} = this.props;

    const ids = Object.keys(selectedFolderEntryMap);
    await deleteEntries({ids});
    clearSelectedFolderEntryIds();
    const totalPages = Math.ceil((folderEntryCount - ids.length) / perpage);
    const nextPage = (page > totalPages) ? totalPages : page;

    await listFolderEntries({folderId: params.id, page: nextPage, perpage});
    this.setState({page: nextPage});
    setSnackBarParams(true, f('folder-entries-has-been-deleted', {count: ids.length}));
    this.updateTableKey();
  };

  renderDeleteButton() {
    const {selectedFolderEntryMap, f} = this.props;
    if (Object.keys(selectedFolderEntryMap).length > 0) {
      return <FlatButton label={f('delete')} icon={} onTouchTap={this.deleteSelectedFolderEntries} />;
    }
  }

  handlePageButtonTouchTap = (page) => {
    this.updateTableKey();
    this.setState({page});
  };

  handleSearchInputChange = (searchKeyword) => {
    if (this.state.searchKeyword !== searchKeyword) {
      this.setState({page: 1});
    }
    this.setState({searchKeyword});
  };

  handleSearchTypeChange = (event, key, searchType) => this.setState({searchType});

  getMatchedCount() {

    const {searchKeyword} = this.state;
    const {folderEntryCount} = this.props;

    if (hasValue(searchKeyword)) {
      return folderEntryCount;
    }
    return 0;
  }

  handleClearSearchButtonTouchTap = () => {
    this.setState({searchKeyword: ''});
    this.refs.searchBar.getWrappedInstance().getWrappedInstance().clear();
  };

  isImporting() {
    const {folder, importingFolderId} = this.props;
    return folder.id === importingFolderId;
  }

  render() {

    const {page, searchType, searchKeyword} = this.state;
    const {f, folder, folderEntryCount, perpage, interfaceFontSizeScalingFactor} = this.props;
    const matchedCount = this.getMatchedCount();
    const buttonFontSize = getFontSize(interfaceFontSizeScalingFactor, 0.9);

    return (

        <TopBar>
          <Breadcrumb>
            <Link to="/">{f('folders')}</Link>
            {f('folder-entries', {folderName: folder.name})}
          </Breadcrumb>

            {this.renderDeleteButton()}
            <FlatButton icon={} labelStyle={{fontSize: buttonFontSize}}
              label={f('add-entry')} onTouchTap={this.goToAddFolderEntryPage} disabled={this.isImporting()} />
            <FlatButton icon={} labelStyle={{fontSize: buttonFontSize}}
              label={f('back')} onTouchTap={hashHistory.goBack} />

        </TopBar>

          <SearchBar ref="searchBar" onInputChange={this.handleSearchInputChange} searchTypes={SEARCH_TYPES}
            searchKeyword={searchKeyword} matchedCount={matchedCount}
            selectedSearchType={searchType} onSearchTypeChange={this.handleSearchTypeChange}
            onClearFilterButtonTouchTap={this.handleClearSearchButtonTouchTap} />
          {this.renderFolderEntries()}
          {(folderEntryCount > perpage) && <Pagination current={page} total={Math.ceil(folderEntryCount / perpage)}
            onButtonTouchTap={this.handlePageButtonTouchTap} />}

    );
  }
}
<|endoftext|>


<commit_before>'use strict';

/*
* States are the controller part of the Voxa's mvc model
* more info at http://voxa.readthedocs.io/en/latest/controllers.html
*/

exports.register = function register(skill) {
  // This event is triggered after new session has started
  skill.onSessionStarted((alexaEvent) => {});
  // This event is triggered before the current session has ended
  skill.onSessionEnded((alexaEvent) => {});
  // This can be used to plug new information in the request
  skill.onRequestStated((alexaEvent) => {});

  /**
   * If you want to handle a specific state onIntent
   * see more http://voxa.readthedocs.io/en/latest/controllers.html#the-onintent-helper
   * See more handlers at http://voxa.readthedocs.io/en/latest/statemachine-skill.html
   */

  skill.onIntent('LaunchIntent', () => ({ reply: 'Intent.Launch', to: 'Overview' }));

  // See how to manage the transition
  // http://voxa.readthedocs.io/en/latest/transition.html
  skill.onIntent('AMAZON.HelpIntent', () => ({ reply: 'Intent.Help', to: 'exit' }));

  skill.onState('exit', () => ({ reply: 'Intent.Exit', to: 'die' }));

  skill.onState('Overview', (alexaEvent) => {
    // Read more about alexaEvent at http://voxa.readthedocs.io/en/latest/alexa-event.html#AlexaEvent
    if (alexaEvent.intent.name === 'AMAZON.YesIntent') {
      return ({ to: 'AMAZON.HelpIntent' });
    }

    if (alexaEvent.intent.name === 'AMAZON.NoIntent') {
      return ({ to: 'exit' });
    }

    return ({ to: 'entry' });
  });

  /**
   * Error handlers
   * See more: http://voxa.readthedocs.io/en/latest/statemachine-skill.html#error-handlers
   */

  skill.onError(() => ({ reply: 'Error.General' }));
  skill.onStateMachineError(() => ({ reply: 'Error.General' }));
  skill.onUnhandledState(() => ({ reply: 'Error.General' }));
};
<commit_msg>fixed typo on onRequestStarted<commit_after>'use strict';

/*
* States are the controller part of the Voxa's mvc model
* more info at http://voxa.readthedocs.io/en/latest/controllers.html
*/

exports.register = function register(skill) {
  // This event is triggered after new session has started
  skill.onSessionStarted((alexaEvent) => {});
  // This event is triggered before the current session has ended
  skill.onSessionEnded((alexaEvent) => {});
  // This can be used to plug new information in the request
  skill.onRequestStarted((alexaEvent) => {});

  /**
   * If you want to handle a specific state onIntent
   * see more http://voxa.readthedocs.io/en/latest/controllers.html#the-onintent-helper
   * See more handlers at http://voxa.readthedocs.io/en/latest/statemachine-skill.html
   */

  skill.onIntent('LaunchIntent', () => ({ reply: 'Intent.Launch', to: 'Overview' }));

  // See how to manage the transition
  // http://voxa.readthedocs.io/en/latest/transition.html
  skill.onIntent('AMAZON.HelpIntent', () => ({ reply: 'Intent.Help', to: 'exit' }));

  skill.onState('exit', () => ({ reply: 'Intent.Exit', to: 'die' }));

  skill.onState('Overview', (alexaEvent) => {
    // Read more about alexaEvent at http://voxa.readthedocs.io/en/latest/alexa-event.html#AlexaEvent
    if (alexaEvent.intent.name === 'AMAZON.YesIntent') {
      return ({ to: 'AMAZON.HelpIntent' });
    }

    if (alexaEvent.intent.name === 'AMAZON.NoIntent') {
      return ({ to: 'exit' });
    }

    return ({ to: 'entry' });
  });

  /**
   * Error handlers
   * See more: http://voxa.readthedocs.io/en/latest/statemachine-skill.html#error-handlers
   */

  skill.onError(() => ({ reply: 'Error.General' }));
  skill.onStateMachineError(() => ({ reply: 'Error.General' }));
  skill.onUnhandledState(() => ({ reply: 'Error.General' }));
};
<|endoftext|>


<commit_before>
/**
 * @file popup.js
 * @author Bryan Hazelbaker <bryan.hazelbaker@gmail.com>
 *
 * @copyright Copyright (c) 2013 Bryan Hazelbaker <bryan.hazelbaker@gmail.com>
 * Released under the MIT license. Read the entire license located in the
 * project root or at http://opensource.org/licenses/mit-license.php
 *
 * @brief Populate fields from background page information.
 *
 * @details Communicates with the background page ae object to use acquire
 * data to be filled into the popup's DOM structure. Mainly concerned with
 * the display of information to the viewer.
 */

// Setup initial values when popup is first opened.
jQuery('document').ready(function($) {
    var background = chrome.extension.getBackgroundPage();
    var AstroEmpires = background.AstroEmpires;
    if (!localStorage['server'] || !localStorage['email'] || !localStorage['password']) {
        var body = jQuery('body');
        body.html('
Please configure first under chrome settings, extensions

After saving configuration it may take up to 60 seconds for data to display.
');
        return;
    }
    // No need to alter the message pointers in the ae object, make a copy
    // instead.
    var ae = jQuery.extend(true, {}, background.ae);
    // Get statistics.
    printValues(ae);
    // Fill in the most recent messages.
    printGuildMessages(ae);
});

/**
 * Update the statistics.
 */
function printValues(ae) {
    jQuery('div.credits-value').html(ae.stats.credits);
    jQuery('div.income-value').html(ae.stats.income + ' per hour');
    jQuery('div.fleetsize-value').html(ae.stats.fleetSize);
    jQuery('div.technology-value').html(ae.stats.technology);
    jQuery('div.level-value').html(ae.stats.level);
    jQuery('div.rank-value').html(ae.stats.rank);
}

/**
 * Update the guild messages.
 */
function printGuildMessages(ae) {
    // Fill in the most recent messages.
    var message = jQuery('div.message-container div.content');
    var msg = ae.msgs.guild.getLast();
    for(i = 0; i < 6; i++) {
        var moment = new Date(msg.time * 1000);
        var date = moment.getMonth() + '/' + moment.getDay();
        var time = moment.getHours() + ':' + moment.getMinutes();
        message.append(
            '
' + date + ' ' + time + ' ' + msg.playerName + '
' +
            '
' + msg.message + '
'
        );
        $('div.name.msg-' + msg.id).click(function () {
            //var id = AstroEmpires.regex(/msg-([0-9]+)/i, $(this).attr('class'), 1, false);
            var msg_body = $(this).next();
            if ($(msg_body).css('display') == 'none') {
                $(msg_body).fadeIn();
            }
            else {
                $(msg_body).fadeOut();
            }
        });
        ae.msgs.guild.getPrev();
    }
}

/**
 * Updating the popup with what we are currently doing.
 *
 * This is called directly from the background page.
 */
function printStatus(data, messageType, ae) {
    var d = new Date();
    var n = d.getTime();
    var status = jQuery('div.ae-status-container div.content');
    status.html(n);
}
<commit_msg>Removing unused commented code.<commit_after>
/**
 * @file popup.js
 * @author Bryan Hazelbaker <bryan.hazelbaker@gmail.com>
 *
 * @copyright Copyright (c) 2013 Bryan Hazelbaker <bryan.hazelbaker@gmail.com>
 * Released under the MIT license. Read the entire license located in the
 * project root or at http://opensource.org/licenses/mit-license.php
 *
 * @brief Populate fields from background page information.
 *
 * @details Communicates with the background page ae object to use acquire
 * data to be filled into the popup's DOM structure. Mainly concerned with
 * the display of information to the viewer.
 */

// Setup initial values when popup is first opened.
jQuery('document').ready(function($) {
    var background = chrome.extension.getBackgroundPage();
    var AstroEmpires = background.AstroEmpires;
    if (!localStorage['server'] || !localStorage['email'] || !localStorage['password']) {
        var body = jQuery('body');
        body.html('
Please configure first under chrome settings, extensions

After saving configuration it may take up to 60 seconds for data to display.
');
        return;
    }
    // No need to alter the message pointers in the ae object, make a copy
    // instead.
    var ae = jQuery.extend(true, {}, background.ae);
    // Get statistics.
    printValues(ae);
    // Fill in the most recent messages.
    printGuildMessages(ae);
});

/**
 * Update the statistics.
 */
function printValues(ae) {
    jQuery('div.credits-value').html(ae.stats.credits);
    jQuery('div.income-value').html(ae.stats.income + ' per hour');
    jQuery('div.fleetsize-value').html(ae.stats.fleetSize);
    jQuery('div.technology-value').html(ae.stats.technology);
    jQuery('div.level-value').html(ae.stats.level);
    jQuery('div.rank-value').html(ae.stats.rank);
}

/**
 * Update the guild messages.
 */
function printGuildMessages(ae) {
    // Fill in the most recent messages.
    var message = jQuery('div.message-container div.content');
    var msg = ae.msgs.guild.getLast();
    for(i = 0; i < 6; i++) {
        var moment = new Date(msg.time * 1000);
        var date = moment.getMonth() + '/' + moment.getDay();
        var time = moment.getHours() + ':' + moment.getMinutes();
        message.append(
            '
' + date + ' ' + time + ' ' + msg.playerName + '
' +
            '
' + msg.message + '
'
        );
        $('div.name.msg-' + msg.id).click(function () {
            var msg_body = $(this).next();
            if ($(msg_body).css('display') == 'none') {
                $(msg_body).fadeIn();
            }
            else {
                $(msg_body).fadeOut();
            }
        });
        ae.msgs.guild.getPrev();
    }
}

/**
 * Updating the popup with what we are currently doing.
 *
 * This is called directly from the background page.
 */
function printStatus(data, messageType, ae) {
    var d = new Date();
    var n = d.getTime();
    var status = jQuery('div.ae-status-container div.content');
    status.html(n);
}
<|endoftext|>


<commit_before>var $error = $('#error');
var tags;
var inputTextValue;

function renderStatus(statusText) {
  document.getElementById('status').textContent = statusText;
}

function searchAgainstTags(searchText){
  console.log(tags);
  if(tags === undefined){
    $error.text("Scanning Images....");

    chrome.tabs.executeScript(null, {file:"js/jquery-1.11.3.min.js"});
    chrome.tabs.executeScript(null, {file:"js/jquery.cookie.js"});
    chrome.tabs.executeScript(null, {file:"url-scraper.js"}, function(data){
      console.log(data);
      tags = JSON.parse(data);

      // url = tags.results[0].url;
      // //url = url.replace("//","\\/\\/");
      // tags = tags.results[0].result.tag.classes;
      searchAgainstTags(searchText);
    });
  }else{
    var check = tags[searchText];
    if(check === undefined){
      $error.text("Nothing Found");
    }else{
      $error.text("Found!");
      var parts = check[0].split("/");
      console.log(check);
        chrome.tabs.executeScript({
          code: '$("html, body").animate({scrollTop : $("img[src$='+"'"+parts[parts.length-1]+"'"+'] || img[src$='+"'"+parts[parts.length-2]+"/"+parts[parts.length-1]+"'"+']").offset().top },1000);'
        });
    }
  }
}

document.addEventListener('DOMContentLoaded', function() {
  $error = $('#error');

  window.onkeyup = keyup;

	function keyup(e) {
  //setting your input text to the global Javascript Variable for every key press
  		inputTextValue = e.target.value;
  		renderStatus(inputTextValue);
      	searchAgainstTags(inputTextValue);
	}
});
<commit_msg>attempted regex<commit_after>var $error = $('#error');
var tags;
var inputTextValue;

function renderStatus(statusText) {
  document.getElementById('status').textContent = statusText;
}

function searchAgainstTags(searchText){
  console.log(tags);
  if(tags === undefined){
    $error.text("Scanning Images....");

    chrome.tabs.executeScript(null, {file:"js/jquery-1.11.3.min.js"});
    chrome.tabs.executeScript(null, {file:"js/jquery.cookie.js"});
    chrome.tabs.executeScript(null, {file:"url-scraper.js"}, function(data){
      console.log(data);
      tags = JSON.parse(data);

      // url = tags.results[0].url;
      // //url = url.replace("//","\\/\\/");
      // tags = tags.results[0].result.tag.classes;
      searchAgainstTags(searchText);
    });
  }else{
    var check = tags[searchText];
    if(check === undefined){
      $error.text("Nothing Found");
    }else{
      $error.text("Found!");
      var parts = check[0].split("/");
      console.log(check);
        chrome.tabs.executeScript({
          code: '$("html, body").animate({scrollTop : $("img[src$='+"'/"+parts[parts.length-1]+"$/'"+'], img[src$='+"'/"+parts[parts.length-2]+"/"+parts[parts.length-1]+"$/'"+']").offset().top },1000);'
        });
    }
  }
}

document.addEventListener('DOMContentLoaded', function() {
  $error = $('#error');

  window.onkeyup = keyup;

	function keyup(e) {
  //setting your input text to the global Javascript Variable for every key press
  		inputTextValue = e.target.value;
  		renderStatus(inputTextValue);
      	searchAgainstTags(inputTextValue);
	}
});
<|endoftext|>


<commit_before>'use strict';

define(['angular'], function(angular) {

  var app = angular.module('portal.main.services', []);

  app.factory('mainService', ['$http', '$sessionStorage', 'miscService', 'SERVICE_LOC', 'APP_FLAGS', function($http, $sessionStorage, miscService, SERVICE_LOC, APP_FLAGS) {
    var prom = $http.get(SERVICE_LOC.sessionInfo, { cache: true});
    var userPromise;

    var getUser = function() {
      if (userPromise) {
        return userPromise;
      }

      userPromise = prom.then(
          function(result, status) { //success function
            if(APP_FLAGS.loginOnLoad) {
              //quick check to make sure you are who your browser says you are
              if($sessionStorage.portal
                && $sessionStorage.portal.username
                && (result.data.person.userName !== $sessionStorage.portal.username
                    ||
                    result.data.person.impersonatedUserName !== $sessionStorage.portal.username)
                ) {
                  console.warn("Thought they were " + $sessionStorage.portal.username +
                   " but session sent back " + result.data.person.userName +". Redirect!");
                  delete $sessionStorage.portal;
                  miscService.redirectUser(302, "Wrong User than populated in session storage.");
              }
            }
            return result.data.person;
          }, function(data, status) { // failure function
            miscService.redirectUser(status, "Get User Info");
          });
      return userPromise;
    };

    return {
      getUser: getUser
    };

  }]);

  return app;

});
<commit_msg>add in check for originalUsername<commit_after>'use strict';

define(['angular'], function(angular) {

  var app = angular.module('portal.main.services', []);

  app.factory('mainService', ['$http', '$sessionStorage', 'miscService', 'SERVICE_LOC', 'APP_FLAGS', function($http, $sessionStorage, miscService, SERVICE_LOC, APP_FLAGS) {
    var prom = $http.get(SERVICE_LOC.sessionInfo, { cache: true});
    var userPromise;

    var getUser = function() {
      if (userPromise) {
        return userPromise;
      }

      userPromise = prom.then(
          function(result, status) { //success function
            if(APP_FLAGS.loginOnLoad) {
              //quick check to make sure you are who your browser says you are
              if($sessionStorage.portal
                && $sessionStorage.portal.username
                && (result.data.person.userName !== $sessionStorage.portal.username
                    ||
                    result.data.person.originalUsername !== $sessionStorage.portal.username)
                ) {
                  console.warn("Thought they were " + $sessionStorage.portal.username +
                   " but session sent back " + result.data.person.userName +". Redirect!");
                  delete $sessionStorage.portal;
                  miscService.redirectUser(302, "Wrong User than populated in session storage.");
              }
            }
            return result.data.person;
          }, function(data, status) { // failure function
            miscService.redirectUser(status, "Get User Info");
          });
      return userPromise;
    };

    return {
      getUser: getUser
    };

  }]);

  return app;

});
<|endoftext|>


<commit_before>var mousePosX = 0;
var mousePosY = 0;

document.addEventListener("mousemove", function(event) {
    mousePosX = event.clientX;
    mousePosY = event.clientY;
});

document.addEventListener("click", function() {
    var dropdowns = document.getElementsByClassName("dropdown");
    for (var i = 0; i < dropdowns.length; ++i) {
        dropdowns[i].setAttribute("hidden", "hidden");
    }
});

var cameFromCtxMenu = false;

var update_list = function() {
    browser.storage.sync.get(null).then(function(items) {
        var storylist = document.getElementById("storylist");
        while (storylist.firstChild) {
            storylist.removeChild(storylist.firstChild);
        }

        for (var sid in items) {
            if (items.hasOwnProperty(sid) && sid) {
                var row = document.createElement("tr");
                var item = document.createElement("td");
                row.appendChild(item)
                item.classList.add("storyitem");

                // Skip this story if it doesn't match a filter
                if (document.getElementById("favfilter").checked && !items[sid]["favoured"]) {
                    continue;
                }
                if (document.getElementById("readfilter").checked && !items[sid]["read"]) {
                    continue;
                }
                if (document.getElementById("pendingfilter").checked && !items[sid]["pending"]) {
                    continue;
                }
                if (document.getElementById("completefilter").checked && (items[sid]["status"] !== 1)) {
                    continue;
                }

                var searchtext = document.getElementById("searchfilter").value;
                if (searchtext != "") {
                    searchtext = new RegExp(searchtext, 'i');
                    if ((items[sid]["title"].search(searchtext) === -1)
                        && (items[sid]["author"].search(searchtext) === -1)) {
                        continue;
                    }
                }

                var extrainfo = [];
                if (items[sid]["favoured"]) {
                    extrainfo.push("Favoured");
                }
                if (items[sid]["read"]) {
                    extrainfo.push("Read");
                }
                if (items[sid]["pending"]) {
                    extrainfo.push("Pending");
                }
                if (typeof items[sid]["status"] == "number") {
                    extrainfo.push(["In-Progress", "Complete", "Abandoned"][items[sid]["status"]]);
                }
                if (items[sid]["rating"]) {
                    extrainfo.push("Rated: " + items[sid]["rating"]);
                }

                var itemtext = "" + items[sid]["title"] +
                                " by " + items[sid]["author"] + "";
                if (extrainfo.length !== 0) {
                    itemtext += '' + extrainfo.join(", ") + "";
                }
                itemtext += "
" + items[sid]["summary"] + "
" + items[sid]["comments"] + "";

                item.innerHTML = itemtext;

                var createClickCallback = function(s) {
                    return function() {
                        browser.tabs.create({
                            url: "https://www.fanfiction.net/s/" + s,
                            active: false
                        });
                    };
                };

                var createRightClickCallback = function(s) {
                    return function() {
                        var dropdown = document.getElementById("storymenu");
                        dropdown.style.left = mousePosX + "px";
                        dropdown.style.top = mousePosY + "px";

                        document.getElementById("storytabopen").addEventListener("click", function() {
                            browser.tabs.create({
                                url: "https://www.fanfiction.net/s/" + s,
                                active: false
                            });

                            dropdown.setAttribute("hidden", "hidden");
                        });

                        document.getElementById("editstorypane").addEventListener("click", function() {
                            browser.storage.sync.get([s]).then(function(items) {
                                document.getElementById("sid").innerHTML = s;
                                document.getElementById("title").innerHTML = items[s]["title"];
                                document.getElementById("author").innerHTML = items[s]["author"];
                                document.getElementById("summary").innerHTML = items[s]["summary"];
                                document.getElementById("favtick").checked = items[s]["favoured"];
                                document.getElementById("readtick").checked = items[s]["read"];
                                document.getElementById("pendingtick").checked = items[s]["pending"];
                                document.getElementById("userrating").value = items[s]["rating"];
                                document.getElementById("comments").value = items[s]["comments"];
                                document.getElementById("status").selectedIndex = items[s]["status"];
                                document.getElementById("delete").disabled = false;

                                dropdown.setAttribute("hidden", "hidden");
                                cameFromCtxMenu = true;
                                document.getElementById("currtab").click();
                            });
                        });

                        dropdown.removeAttribute("hidden");
                    };
                };

                item.addEventListener("click", createClickCallback(sid));
                item.addEventListener("contextmenu", createRightClickCallback(sid));

                storylist.appendChild(row);
            }
        }
    });
};

var fetch_tab_story = function() {
    browser.tabs.query({active: true, currentWindow: true}).then(function(tabs) {
        browser.tabs.sendMessage(tabs[0].id, {"type": "ff-data"}).then(function(response) {
            document.getElementById("title").innerHTML = response["title"];
            document.getElementById("author").innerHTML = response["author"];
            document.getElementById("summary").innerHTML = response["summary"];
            document.getElementById("sid").innerHTML = response["id"];

            var sid = document.getElementById("sid").innerHTML;
            browser.storage.sync.get([sid]).then(function(items) {
                if (items[sid] !== undefined) {
                    document.getElementById("favtick").checked = items[sid]["favoured"];
                    document.getElementById("readtick").checked = items[sid]["read"];
                    document.getElementById("pendingtick").checked = items[sid]["pending"];
                    document.getElementById("userrating").value = items[sid]["rating"];
                    document.getElementById("comments").value = items[sid]["comments"];
                    document.getElementById("status").selectedIndex = items[sid]["status"];
                    document.getElementById("delete").disabled = false;
                } else {
                    document.getElementById("favtick").checked = false;
                    document.getElementById("readtick").checked = false;
                    document.getElementById("pendingtick").checked = false;
                    document.getElementById("userrating").value = "";
                    document.getElementById("comments").value = "";
                    document.getElementById("status").selectedIndex = response["status"];
                }
            });
        }).catch(function() {
            document.getElementById("savedtab").click();
        });

        browser.tabs.sendMessage(tabs[0].id, {"type": "get-user"}).then(function(response) {
            if (response["loggedin"]) {
                document.getElementById("notloggedin").hidden = true;
                document.getElementById("areloggedin").hidden = false;
                document.getElementById("username").innerHTML = response["username"];
            }
        });
    });
};

document.addEventListener("DOMContentLoaded", function() {
    var buttons = document.getElementsByClassName("button");

    for (var i = 0; i < buttons.length; i++) {
        buttons[i].addEventListener("click", function() {
            var buttons = document.getElementsByClassName("button");
            var containers = document.getElementsByClassName("container");

            for (var i = 0; i < buttons.length; i++) {
                if (this === buttons[i]) {
                    buttons[i].classList.add("active");
                    containers[i].removeAttribute("hidden");
                } else {
                    buttons[i].classList.remove("active");
                    containers[i].setAttribute("hidden", "hidden");
                }
            }
        });
    }

    document.getElementById("currtab").addEventListener("click", function() {
        if (!cameFromCtxMenu) {
            fetch_tab_story();
        }
        else {
            cameFromCtxMenu = false;
        }
    });

    document.getElementById("savedtab").addEventListener("click", function() {
        document.getElementById("searchfilter").focus();
    });

    document.getElementById("save").addEventListener("click", function() {
        var store = {};

        var sid = document.getElementById("sid").innerHTML;
        store[sid] = {};

        store[sid]["title"] = document.getElementById("title").innerHTML;
        store[sid]["author"] = document.getElementById("author").innerHTML;
        store[sid]["summary"] = document.getElementById("summary").innerHTML;
        store[sid]["favoured"] = document.getElementById("favtick").checked;
        store[sid]["read"] = document.getElementById("readtick").checked;
        store[sid]["pending"] = document.getElementById("pendingtick").checked;
        store[sid]["rating"] = document.getElementById("userrating").value;
        store[sid]["comments"] = document.getElementById("comments").value;
        store[sid]["status"] = document.getElementById("status").selectedIndex;

        browser.storage.sync.set(store).then(function() {
            document.getElementById("delete").disabled = false;
            update_list();
        });
    });

    document.getElementById("delete").addEventListener("click", function() {
        var sid = document.getElementById("sid").innerHTML;
        browser.storage.sync.remove([sid]).then(update_list);
    });

    fetch_tab_story();

    var databox = document.getElementById("internaldata");
    var exbutton = document.getElementById("export");
    var inbutton = document.getElementById("import");

    databox.addEventListener("paste", function() {
        inbutton.disabled = false;
    });

    exbutton.addEventListener("click", function() {
        browser.storage.sync.get(null).then(function(items) {
            databox.value = JSON.stringify(items, null, 1);
            inbutton.disabled = false;
        });
    });

    var filterinputs = document.getElementById("filters").childNodes;

    for (var i = 0; i < filterinputs.length; ++i) {
        if (filterinputs[i].tagName == "INPUT") {
            if (filterinputs[i].type == "checkbox") {
                filterinputs[i].addEventListener("click", update_list);
            }
            else if (filterinputs[i].type == "search") {
                filterinputs[i].addEventListener("keydown", update_list);
            }
        }
    }

    inbutton.addEventListener("click", function() {
        browser.storage.sync.clear().then(function(items) {
            browser.storage.sync.set(JSON.parse(databox.value)).then(function() {
                update_list();
            });
        });
    });

    update_list();
});
<commit_msg>Default click in Saved Stories opens story in current tab and closes popup.<commit_after>var mousePosX = 0;
var mousePosY = 0;

document.addEventListener("mousemove", function(event) {
    mousePosX = event.clientX;
    mousePosY = event.clientY;
});

document.addEventListener("click", function() {
    var dropdowns = document.getElementsByClassName("dropdown");
    for (var i = 0; i < dropdowns.length; ++i) {
        dropdowns[i].setAttribute("hidden", "hidden");
    }
});

var cameFromCtxMenu = false;

var update_list = function() {
    browser.storage.sync.get(null).then(function(items) {
        var storylist = document.getElementById("storylist");
        while (storylist.firstChild) {
            storylist.removeChild(storylist.firstChild);
        }

        for (var sid in items) {
            if (items.hasOwnProperty(sid) && sid) {
                var row = document.createElement("tr");
                var item = document.createElement("td");
                row.appendChild(item)
                item.classList.add("storyitem");

                // Skip this story if it doesn't match a filter
                if (document.getElementById("favfilter").checked && !items[sid]["favoured"]) {
                    continue;
                }
                if (document.getElementById("readfilter").checked && !items[sid]["read"]) {
                    continue;
                }
                if (document.getElementById("pendingfilter").checked && !items[sid]["pending"]) {
                    continue;
                }
                if (document.getElementById("completefilter").checked && (items[sid]["status"] !== 1)) {
                    continue;
                }

                var searchtext = document.getElementById("searchfilter").value;
                if (searchtext != "") {
                    searchtext = new RegExp(searchtext, 'i');
                    if ((items[sid]["title"].search(searchtext) === -1)
                        && (items[sid]["author"].search(searchtext) === -1)) {
                        continue;
                    }
                }

                var extrainfo = [];
                if (items[sid]["favoured"]) {
                    extrainfo.push("Favoured");
                }
                if (items[sid]["read"]) {
                    extrainfo.push("Read");
                }
                if (items[sid]["pending"]) {
                    extrainfo.push("Pending");
                }
                if (typeof items[sid]["status"] == "number") {
                    extrainfo.push(["In-Progress", "Complete", "Abandoned"][items[sid]["status"]]);
                }
                if (items[sid]["rating"]) {
                    extrainfo.push("Rated: " + items[sid]["rating"]);
                }

                var itemtext = "" + items[sid]["title"] +
                                " by " + items[sid]["author"] + "";
                if (extrainfo.length !== 0) {
                    itemtext += '' + extrainfo.join(", ") + "";
                }
                itemtext += "
" + items[sid]["summary"] + "
" + items[sid]["comments"] + "";

                item.innerHTML = itemtext;

                var createClickCallback = function(s) {
                    return function() {
                        browser.tabs.query({active: true, currentWindow: true}).then(function(tabs) {
                            browser.tabs.update(tabs[0].id, {
                                url: "https://www.fanfiction.net/s/" + s,
                                active: true
                            });

                            window.close();
                        });
                    };
                };

                var createRightClickCallback = function(s) {
                    return function() {
                        var dropdown = document.getElementById("storymenu");
                        dropdown.style.left = mousePosX + "px";
                        dropdown.style.top = mousePosY + "px";

                        document.getElementById("storytabopen").addEventListener("click", function() {
                            browser.tabs.create({
                                url: "https://www.fanfiction.net/s/" + s,
                                active: false
                            });

                            dropdown.setAttribute("hidden", "hidden");
                        });

                        document.getElementById("editstorypane").addEventListener("click", function() {
                            browser.storage.sync.get([s]).then(function(items) {
                                document.getElementById("sid").innerHTML = s;
                                document.getElementById("title").innerHTML = items[s]["title"];
                                document.getElementById("author").innerHTML = items[s]["author"];
                                document.getElementById("summary").innerHTML = items[s]["summary"];
                                document.getElementById("favtick").checked = items[s]["favoured"];
                                document.getElementById("readtick").checked = items[s]["read"];
                                document.getElementById("pendingtick").checked = items[s]["pending"];
                                document.getElementById("userrating").value = items[s]["rating"];
                                document.getElementById("comments").value = items[s]["comments"];
                                document.getElementById("status").selectedIndex = items[s]["status"];
                                document.getElementById("delete").disabled = false;

                                dropdown.setAttribute("hidden", "hidden");
                                cameFromCtxMenu = true;
                                document.getElementById("currtab").click();
                            });
                        });

                        dropdown.removeAttribute("hidden");
                    };
                };

                item.addEventListener("click", createClickCallback(sid));
                item.addEventListener("contextmenu", createRightClickCallback(sid));

                storylist.appendChild(row);
            }
        }
    });
};

var fetch_tab_story = function() {
    browser.tabs.query({active: true, currentWindow: true}).then(function(tabs) {
        browser.tabs.sendMessage(tabs[0].id, {"type": "ff-data"}).then(function(response) {
            document.getElementById("title").innerHTML = response["title"];
            document.getElementById("author").innerHTML = response["author"];
            document.getElementById("summary").innerHTML = response["summary"];
            document.getElementById("sid").innerHTML = response["id"];

            var sid = document.getElementById("sid").innerHTML;
            browser.storage.sync.get([sid]).then(function(items) {
                if (items[sid] !== undefined) {
                    document.getElementById("favtick").checked = items[sid]["favoured"];
                    document.getElementById("readtick").checked = items[sid]["read"];
                    document.getElementById("pendingtick").checked = items[sid]["pending"];
                    document.getElementById("userrating").value = items[sid]["rating"];
                    document.getElementById("comments").value = items[sid]["comments"];
                    document.getElementById("status").selectedIndex = items[sid]["status"];
                    document.getElementById("delete").disabled = false;
                } else {
                    document.getElementById("favtick").checked = false;
                    document.getElementById("readtick").checked = false;
                    document.getElementById("pendingtick").checked = false;
                    document.getElementById("userrating").value = "";
                    document.getElementById("comments").value = "";
                    document.getElementById("status").selectedIndex = response["status"];
                }

                document.getElementById("comments").focus();
            });
        }).catch(function() {
            document.getElementById("savedtab").click();
        });

        browser.tabs.sendMessage(tabs[0].id, {"type": "get-user"}).then(function(response) {
            if (response["loggedin"]) {
                document.getElementById("notloggedin").hidden = true;
                document.getElementById("areloggedin").hidden = false;
                document.getElementById("username").innerHTML = response["username"];
            }
        });
    });
};

document.addEventListener("DOMContentLoaded", function() {
    var buttons = document.getElementsByClassName("button");

    for (var i = 0; i < buttons.length; i++) {
        buttons[i].addEventListener("click", function() {
            var buttons = document.getElementsByClassName("button");
            var containers = document.getElementsByClassName("container");

            for (var i = 0; i < buttons.length; i++) {
                if (this === buttons[i]) {
                    buttons[i].classList.add("active");
                    containers[i].removeAttribute("hidden");
                } else {
                    buttons[i].classList.remove("active");
                    containers[i].setAttribute("hidden", "hidden");
                }
            }
        });
    }

    document.getElementById("currtab").addEventListener("click", function() {
        if (!cameFromCtxMenu) {
            fetch_tab_story();
        }
        else {
            cameFromCtxMenu = false;
            document.getElementById("comments").focus();
        }
    });

    document.getElementById("savedtab").addEventListener("click", function() {
        document.getElementById("searchfilter").focus();
    });

    document.getElementById("save").addEventListener("click", function() {
        var store = {};

        var sid = document.getElementById("sid").innerHTML;
        store[sid] = {};

        store[sid]["title"] = document.getElementById("title").innerHTML;
        store[sid]["author"] = document.getElementById("author").innerHTML;
        store[sid]["summary"] = document.getElementById("summary").innerHTML;
        store[sid]["favoured"] = document.getElementById("favtick").checked;
        store[sid]["read"] = document.getElementById("readtick").checked;
        store[sid]["pending"] = document.getElementById("pendingtick").checked;
        store[sid]["rating"] = document.getElementById("userrating").value;
        store[sid]["comments"] = document.getElementById("comments").value;
        store[sid]["status"] = document.getElementById("status").selectedIndex;

        browser.storage.sync.set(store).then(function() {
            document.getElementById("delete").disabled = false;
            update_list();
        });
    });

    document.getElementById("delete").addEventListener("click", function() {
        var sid = document.getElementById("sid").innerHTML;
        browser.storage.sync.remove([sid]).then(update_list);
    });

    fetch_tab_story();

    var databox = document.getElementById("internaldata");
    var exbutton = document.getElementById("export");
    var inbutton = document.getElementById("import");

    databox.addEventListener("paste", function() {
        inbutton.disabled = false;
    });

    exbutton.addEventListener("click", function() {
        browser.storage.sync.get(null).then(function(items) {
            databox.value = JSON.stringify(items, null, 1);
            inbutton.disabled = false;
        });
    });

    var filterinputs = document.getElementById("filters").childNodes;

    for (var i = 0; i < filterinputs.length; ++i) {
        if (filterinputs[i].tagName == "INPUT") {
            if (filterinputs[i].type == "checkbox") {
                filterinputs[i].addEventListener("click", update_list);
            }
            else if (filterinputs[i].type == "search") {
                filterinputs[i].addEventListener("keydown", update_list);
            }
        }
    }

    inbutton.addEventListener("click", function() {
        browser.storage.sync.clear().then(function(items) {
            browser.storage.sync.set(JSON.parse(databox.value)).then(function() {
                update_list();
            });
        });
    });

    update_list();
});
<|endoftext|>