/* * app.api.js * Ajax api helper module */ /*jslint browser : true, continue : true, devel : true, indent : 2, maxerr : 50, newcap : true, nomen : true, plusplus : true, regexp : true, sloppy : true, vars : false, white : true */ /*global $, io, app */ app.api = (function () { 'use strict'; var initModule, getAuthHeaderObject, GZAppVersion, get, remove, create, update, uploadFile, doSync, getListFromStore, putListInStore, goToNextList, getActiveList, replaceActiveList, renameActiveList, toggleDeleteActiveList, getActiveListIndex, replaceRecordInStore, insertRecordInStore, getRecordFromStore, getListItemCoordinates, setActiveListId, getActiveListId, newList ; GZAppVersion = "2.0"; ////////////////////////////////////////////////////////////////////////////////////// // NOT AUTHORIZED ERROR HANDLER $(document).ajaxError(function (event, jqxhr, settings, thrownError) { //unauthorized? Trigger logout which will trigger login after clearing creds if (jqxhr.status == 401) { window.location.replace('#!/logout'); } }); ////////////////////////////////////////////////////////////////////////////////////// // UTILITY /////////////////////////////////////////////////////////// // Return the auth token header // // getAuthHeaderObject = function () { return { "Authorization": "Bearer " + app.shell.stateMap.user.token }; } /////////////////////////////////////////////////////////// // Fetch the list from local storage // // getListFromStore = function () { return store.get('pecklist.list'); } /////////////////////////////////////////////////////////// // Replace the list in local store // // putListInStore = function (theList) { store.set('pecklist.list', theList); } /////////////////////////////////////////////////////////// // Get the active list id or first if active not found // getActiveListId = function (theId) { var ret = store.get('pecklist.activeListId'); //validate it's ok var l = app.api.getListFromStore(); var firstListId = l[0].id;//get a default in case it's not found var len = l.length, i = 0; for (i; i < len; i++) { if (l[i].id == ret) { return ret; } } //if we're here then it's not a valid id so use the first one instead and set it store.set('pecklist.activeListId', firstListId); return firstListId; } /////////////////////////////////////////////////////////// // Set the active list id // // setActiveListId = function (theId) { if (theId) { store.set('pecklist.activeListId', theId); } } /////////////////////////////////////////////////////////// // ADVANCE ACTIVE LIST ID TO NEXT LIST // // goToNextList = function () { var l = getListFromStore(); var allLength = l.length; //is there more than one list? if (allLength < 2) { //Nope return; } //figure out what the next list id should be var currentIndex = getActiveListIndex(); var highestPossibleIndex = allLength - 1; //are we already at the last list? if (currentIndex == highestPossibleIndex) { //go to first list (wrap) setActiveListId(l[0].id); return; } //advance to the next list setActiveListId(l[currentIndex + 1].id); return; } ////////////////////////////// // GET LIST INDEX // getActiveListIndex = function () { var activeListId = getActiveListId(); var l = app.api.getListFromStore(); var len = l.length, i = 0; for (i; i < len; i++) { if (l[i].id == activeListId) { return i; } } //This should never happen, if it does something is very wrong: throw new Error("Error: app.main.js::getActiveListIndex - active list ID not found in list store"); } /////////////////////////// // GET ACTIVE LIST // getActiveList = function () { var activeListId = getActiveListId(); var l = app.api.getListFromStore(); var len = l.length, i = 0; for (i; i < len; i++) { if (l[i].id == activeListId) { return l[i]; } } //This should never happen, if it does something is very wrong: throw new Error("Error: app.main.js::getActiveList - activeListId not found in list store"); } /////////////////////////// // CREATE NEW LIST // newList = function () { var l = app.api.getListFromStore(); var newListRecord={ id:"NEW_"+ _.now(), name: "New list "+Date(), v:1, name_v:1, items:[] } l.push(newListRecord); app.api.putListInStore(l); setActiveListId(newListRecord.id); } /////////////////////////// // RENAME ACTIVE LIST // renameActiveList = function (newName) { var activeListId = getActiveListId(); var l = app.api.getListFromStore(); var len = l.length, i = 0; for (i; i < len; i++) { if (l[i].id == activeListId) { l[i].name = newName; putListInStore(l); return; } } //This should never happen, if it does something is very wrong: throw new Error("Error: app.main.js::renameActiveList - activeListId not found in list store"); } /////////////////////////// // DELETE ACTIVE LIST // toggleDeleteActiveList = function () { var activeListId = getActiveListId(); var l = app.api.getListFromStore(); var len = l.length, i = 0; for (i; i < len; i++) { if (l[i].id == activeListId) { if (l[i].deleted) { delete l[i].deleted; } else { l[i].deleted = true;//tag it as deleted } putListInStore(l); return; } } //This should never happen, if it does something is very wrong: throw new Error("Error: app.main.js::toggleDeleteActiveList - activeListId not found in list store"); } /////////////////////////// // REPLACE ACTIVE LIST // replaceActiveList = function (replacementList) { var activeListId = getActiveListId(); var l = app.api.getListFromStore(); var len = l.length, i = 0; for (i; i < len; i++) { if (l[i].id == activeListId) { l[i] = replacementList; putListInStore(l); return; } } //This should never happen, if it does something is very wrong: throw new Error("Error: app.main.js::replaceActiveList - activeListId not found in list store"); } ////////////////////////////// // GET LIST ITEM CO-ORDINATES // getListItemCoordinates = function (itemId) { var allLists = app.api.getListFromStore(); var allLength = allLists.length, j = 0; for (j; j < allLength; j++) { //iterate the list and find it var len = allLists[j].items.length, i = 0; for (i; i < len; i++) { if (allLists[j].items[i].id == itemId) { return { listIndex: j, itemIndex: i }; } } } //This should never happen, if it does something is very wrong: throw new Error("Error: app.main.js::getListItemCoordinates - List item ID not found in list store"); } /////////////////////////// // GET RECORD FROM STORE // getRecordFromStore = function (itemId) { var co = getListItemCoordinates(itemId); var allLists = app.api.getListFromStore(); return allLists[co.listIndex].items[co.itemIndex]; } /////////////////////////// // REPLACE RECORD IN STORE // replaceRecordInStore = function (itemId, replacementRecord) { var co = getListItemCoordinates(itemId); var l = app.api.getListFromStore(); //Todo: is this the proper way to do it? l[co.listIndex].items[co.itemIndex] = replacementRecord; app.api.putListInStore(l); } /////////////////////////// // INSERT RECORD IN STORE // insertRecordInStore = function (newRecord) { var activeListIndex = getActiveListIndex(); var l = app.api.getListFromStore(); l[activeListIndex].items.push(newRecord); app.api.putListInStore(l); } ////////////////////////////////////////////////////////////////////////////////////// // PECKLIST SPECIFIC ROUTES ////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// // // DOSYNC - Synchronize the stored data // doSync = function (callback) { //get the list from the store var theList = getListFromStore(); $.ajax({ method: "post", dataType: "json", url: app.shell.stateMap.apiUrl + 'sync', headers: getAuthHeaderObject(), contentType: 'application/json; charset=utf-8', data: JSON.stringify(theList), success: function (ret, textStatus) { //Put the new list in the store putListInStore(JSON.parse(ret)); callback({ ok: 1 }); }, error: function (jqXHR, textStatus, errorThrown) { callback({ error: 1, msg: textStatus + '\n' + errorThrown, error_detail: {} }); } }); } //////////////////////////////////////////////////////////////////////////////////////////////////////// // STANDARD API CORE ROUTES // //////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// //Create //Route app.post('/api/:obj_type/create', function (req, res) { // create = function (apiRoute, objData, callback) { $.ajax({ method: "post", dataType: "json", url: app.shell.stateMap.apiUrl + apiRoute, headers: getAuthHeaderObject(), contentType: 'application/json; charset=utf-8', data: JSON.stringify(objData), success: function (data, textStatus) { callback(data); }, error: function (jqXHR, textStatus, errorThrown) { callback({ error: 1, msg: textStatus + '\n' + errorThrown, error_detail: {} }); } }); } ///////////////// //Get - get anything, the caller provides the route, this should replace most legacy get // get = function (apiRoute, callback) { $.ajax({ method: "GET", dataType: "json", url: app.shell.stateMap.apiUrl + apiRoute, headers: getAuthHeaderObject(), success: function (data, textStatus) { callback(data); }, error: function (jqXHR, textStatus, errorThrown) { callback({ error: 1, msg: textStatus + '\n' + errorThrown, error_detail: {} }); } }); } //////////////////// /////////////////////////////////////////////////////////// //Update //route: app.post('/api/:obj_type/update/:id', function (req, res) { // update = function (objType, objData, callback) { var theId; if (!objData.id) { return callback({ error: 1, msg: 'app.api.js::update->Error: missing id field in update document', error_detail: objData }); } theId = objData.id; $.ajax({ method: "put", dataType: "json", url: app.shell.stateMap.apiUrl + objType + '/' + theId, headers: getAuthHeaderObject(), contentType: 'application/json; charset=utf-8', data: JSON.stringify(objData), success: function (data, textStatus) { if (data == null) { data = { ok: 1 }; } callback(data); }, error: function (jqXHR, textStatus, errorThrown) { callback({ error: 1, msg: textStatus + '\n' + errorThrown, error_detail: {} }); } }); } /////////////////////////////////////////////////////////// //remove Item remove = function (apiRoute, callback) { $.ajax({ method: "DELETE", dataType: "json", url: app.shell.stateMap.apiUrl + apiRoute, headers: getAuthHeaderObject(), success: function (data, textStatus) { callback(data); }, error: function (jqXHR, textStatus, errorThrown) { callback({ error: 1, msg: textStatus + '\n' + errorThrown, error_detail: {} }); } }); } /////////////////////////////////////////////////////////// // uploadFile // (ajax route to upload a file) // uploadFile = function (apiRoute, objData, callback) { $.ajax({ method: "post", dataType: "json", url: app.shell.stateMap.apiUrl + apiRoute, headers: getAuthHeaderObject(), contentType: false, processData: false, data: objData, success: function (data, textStatus) { callback(data); }, error: function (jqXHR, textStatus, errorThrown) { callback({ error: 1, msg: textStatus + '\n' + errorThrown, error_detail: {} }); } }); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// initModule = function () { }; return { initModule: initModule, getAuthHeaderObject: getAuthHeaderObject, GZAppVersion: GZAppVersion, get: get, remove: remove, create: create, update: update, uploadFile: uploadFile, doSync: doSync, getListFromStore: getListFromStore, putListInStore: putListInStore, goToNextList: goToNextList, getActiveList: getActiveList, replaceActiveList: replaceActiveList, getActiveListIndex: getActiveListIndex, replaceRecordInStore: replaceRecordInStore, insertRecordInStore: insertRecordInStore, getRecordFromStore: getRecordFromStore, getListItemCoordinates: getListItemCoordinates, renameActiveList: renameActiveList, toggleDeleteActiveList: toggleDeleteActiveList, newList: newList }; }());