/** * * Client-Side nosql Firebase Realtime Database save management. * @link https://flatte.github.io/Flatte-Web/ * @version v.1.0.1-beta.88 - Tue Sep 05 2017 21:11:41 GMT+0300 (Türkiye Standart Saati) * * Copyright (c) 2017 Flatte - Sezer Ekinci , Kaan Ekinci * @license MIT License, https://opensource.org/licenses/MIT * * @author Sezer Ekinci * @author Kaan Ekinci * * @Controbutors https://github.com/Flatte/Flatte-Web/graphs/contributors * */ !function(){"use strict";function flatte($q,$filter,$timeout){function checkConnection(){return $q(function(e,t){if(!settings.con||!settings.con.database){var n={code:"FB000",message:"Connection Error: settings.con is not defined."};return console.error("[Flatte] Connection Error: ",n),t(n),!1}settings.con.database().ref(".info/connected").once("value",function(t){settings.debug&&console.info("%c♣ [Flatte] Connection Success.","color:#3883fa;"),e(!0)},function(e){return settings.debug&&console.error("[Flatte] Connection Error: ",e),t(e),!1})})}function settings(e,t){var n;if(t)for(n in this.settings)"settings"!==n&&this.settings.hasOwnProperty(n)&&delete this.settings[n];if(e)for(n in e)this.settings[n]=e[n];return this.settings}function debug(e){f.settings().debug&&(angular.isObject(e)?console.info("%c♣ ["+e.code+"] "+e.message,"color:#3883fa;"):console.info("%c♣ "+e,"color:#3883fa;"))}function serial(e){var t;return angular.forEach(e,function(e,n){t=t?t.then(e).catch(function(e){return $q.reject(e)}):e()}),t||$q.when()}function deepExtend(e,t){for(var n in t)t[n]&&t[n].constructor&&t[n].constructor===Object?(e[n]=e[n]||{},deepExtend(e[n],t[n])):e[n]=t[n];return e}function doAction(saveObjects,progress){function createAction(){return f.debug("Create action."),progress&&progress[guid].count++,progress&&(progress[guid].message="Create action..."),$q(function(e,t){if(f.debug("Set action container."),doAction.var[guid]={log:{startedAt:getTime()},objects:{},results:{},appliedManifest:[],eliminatedCodes:["01 - Parent result has been found."]},f.debug("Check sent data"),!saveObjects){var n={code:"F001",message:"Object not found! Please send object first."};return endAction(n),t(n),!1}if(!angular.isArray(saveObjects)){var n={code:"F002",message:"Object is not array! Please send object as an array."};return endAction(n),t(n),!1}e()})}function createObjects(){f.debug("Create objects."),progress&&progress[guid].count++,progress&&(progress[guid].message="Create objects...");var e=[];return angular.forEach(saveObjects,function(t){e.push($q(function(e,n){if(t.ref||(t.ref=""),!t.data){var a={code:"F004",message:"Object data not found! Please send object data first. (ref: "+t.ref+")"};return endAction(a),n(a),!1}doAction.var[guid].objects[t.ref]={ref:t.ref,data:t.data,set:t.set,$action:"delete"===t.data?"delete":"save",$exists:{},$ids:{},$ref:""!==t.ref&&"/"!==t.ref?t.ref.split("/"):[],$results:{},$eliminateds:{}},"delete"!==t.data&&(doAction.var[guid].objects[t.ref].$exists[t.ref]=!0),createLoopData(doAction.var[guid].objects[t.ref]).then(function(){e()}).catch(function(e){return n(e),!1})}))}),$q.all(e)}function getDbData(e){return $q(function(t,n){firebase.database().ref(f.settings().baseRef+"/"+e).once("value",function(e){var n={};angular.forEach(e.val(),function(e,t){n[t]=e}),t(n)},function(e){return n(e),!1})})}function createExists(e,t,n){var a=[];return angular.forEach(t,function(t,o){a.push($q(function(a,i){var r=n?angular.copy(n):[];r.push(o),doAction.var[guid].objects[e].$exists[r.join("/")]=!0,angular.isObject(t)?createExists(e,t,r).then(function(){a()}).catch(function(e){return i(e),!1}):a()}))}),$q.all(a)}function createLoopData(e){return f.debug("Create loop data."),progress&&progress[guid].count++,progress&&(progress[guid].message="Create loop data..."),$q(function(t,n){"save"!==e.$action||e.set?getDbData(e.ref).then(function(a){e.set?createExists(e.ref,e.data,e.$ref).then(function(){doAction.var[guid].objects[e.ref].data=deepExtend(a,doAction.var[guid].objects[e.ref].data),t()}).catch(function(e){return n(e),!1}):(doAction.var[guid].objects[e.ref].data=a,t())}).catch(function(e){return n(e),!1}):t()})}function perform(){f.debug("Perform."),progress&&progress[guid].count++,progress&&(progress[guid].message="Perform...");var e=[];return angular.forEach(doAction.var[guid].objects,function(t){e.push($q(function(e,n){createIdPaths(t.ref,t.$ref).then(function(a){applyManifest(t.ref,t.data,t.$ref,a).then(function(){e()}).catch(function(e){return n(e),!1})}).catch(function(e){return n(e),!1})})),e.push($q(function(e,n){loopData(t.ref,t.data,t.$ref).then(function(){e()}).catch(function(e){return n(e),!1})}))}),$q.all(e)}function loopData(e,t,n){var a=[];return angular.forEach(t,function(t,o){var i=n?angular.copy(n):[];i.push(o),a.push($q(function(n,a){angular.isObject(t)?loopData(e,t,i).then(function(){n()}).catch(function(e){return a(e),!1}):n()})),a.push($q(function(n,a){createIdPaths(e,i).then(function(o){applyManifest(e,t,i,o).then(function(){n()}).catch(function(e){return a(e),!1})}).catch(function(e){return a(e),!1})}))}),$q.all(a)}function createIdPaths(ref,path){function findID(findPath){var promises=[],ID=!1;return angular.forEach(eval("f.settings().manifest"+(findPath.length>0?"['"+findPath.join("'].childs['")+"'].childs":"")),function(e,t){promises.push($q(function(n,a){e.hasOwnProperty("_q")&&e._q.hasOwnProperty("ID")&&(ID=t),n()}))}),$q(function(e){$q.all(promises).then(function(t){e(ID)}).catch(function(e){return reject(e),!1})})}var promises=[],newPath=[],hasItem=!1,notFound=!1;return angular.forEach(path,function(item){promises.push(function(){return $q(function(resolve,reject){try{hasItem=eval("f.settings().manifest"+(newPath.length>0?"['"+newPath.join("'].childs['")+"'].childs":"")+".hasOwnProperty('"+item+"')")}catch(e){hasItem=!1}hasItem?(newPath.push(item),resolve()):findID(newPath).then(function(e){e?newPath.push(e):notFound=notFound||!0,resolve()}).catch(function(e){return reject(e),!1})})})}),$q(function(e,t){f.serial(promises).then(function(){e(!notFound&&newPath)}).catch(function(e){return t(e),!1})})}function applyManifest(ref,data,path,manifestPath){return $q(function(resolve,reject){var manifest={},promises=[],action;action=doAction.var[guid].objects[ref].$exists[path.join("/")]||"permanent"!==doAction.var[guid].objects[ref].set?"permanent"!==doAction.var[guid].objects[ref].set&&("delete"===doAction.var[guid].objects[ref].$action||"save"===doAction.var[guid].objects[ref].$action&&!doAction.var[guid].objects[ref].$exists[path.join("/")]&&doAction.var[guid].objects[ref].set)?"delete":null===data?"delete":"save":"setNull",manifest=!1;try{manifest=eval("f.settings().manifest"+(manifestPath.length>0?"['"+manifestPath.join("'].childs['")+"']":"")+"._q")}catch(e){return manifest=!1,reject(e),!1}manifestPath.length>0&&!doAction.var[guid].appliedManifest.hasOwnProperty(manifestPath.join("/"))&&doAction.var[guid].appliedManifest.push(manifestPath.join("/"));for(var command in commands)promises.push($q(function(e,t){commands[command](ref,data,path,manifest&&manifest.hasOwnProperty(command)&&""!==manifest[command]?manifest[command]:null,action,manifestPath).then(function(t){angular.extend(doAction.var[guid].objects[ref].$results,t),e()}).catch(function(e){return t(e),!1})}));$q.all(promises).then(function(){resolve()}).catch(function(e){return reject(e),!1})})}function createFinalResults(){function e(){function e(e,t){var n=[];return Object.keys(doAction.var[guid].objects[e].$results).reverse().map(function(a){n.push($q(function(n,o){a!==t&&a.split("/").slice(0,t.split("/").length).join("/")===t&&(doAction.var[guid].objects[e].$eliminateds[a]="[01] "+doAction.var[guid].objects[e].$results[a],delete doAction.var[guid].objects[e].$results[a]),n()}))}),$q(function(e,t){$q.all(n).then(function(){e()}).catch(function(e){return t(e),!1})})}function t(t){var n=[];return Object.keys(doAction.var[guid].objects[t].$results).reverse().map(function(a){n.push(function(){$q(function(n,o){angular.isObject(doAction.var[guid].objects[t].$results[a])?(delete doAction.var[guid].objects[t].$results[a],n()):void 0!==doAction.var[guid].objects[t].$results[a]&&e(t,a).then(function(e){n()}).catch(function(e){return o(e),!1})})})}),f.serial(n)}var n=[];return angular.forEach(doAction.var[guid].objects,function(e){n.push($q(function(n,a){t(e.ref).then(function(){n()}).catch(function(e){return a(e),!1})}))}),$q.all(n)}function t(){var e=[];return angular.forEach(doAction.var[guid].objects,function(t){e.push($q(function(e,n){replacePredefined(t.$results).then(function(n){doAction.var[guid].objects[t.ref].$results=n,angular.extend(doAction.var[guid].results,n),e()}).catch(function(e){return n(e),!1})}))}),$q.all(e)}return f.debug("Create final results."),progress&&progress[guid].count++,progress&&(progress[guid].message="Create final results..."),f.serial([e,t])}function replacePredefined(e){var t=[],n={};return angular.forEach(e,function(e,a){t.push($q(function(t,o){var i,r;"string"==typeof e?(r=e.replace(/\([^\)]*\)/g,"()")?e.replace(/\([^\)]*\)/g,"()").replace("()",""):e,r&&(i=e.match(/\([^\)]*\)/g)),i&&(i=i[0].replace("(","").replace(")",""))):r=e,n[a]=f.settings().predefined.hasOwnProperty(r)?"function"==typeof f.settings().predefined[r]?f.settings().predefined[r](i):f.settings().predefined[r]:r,t()}))}),$q(function(e,a){$q.all(t).then(function(){e(n)})})}function update(){return f.debug("Run Update."),progress&&progress[guid].count++,progress&&(progress[guid].message="Run results..."),$q(function(e,t){try{firebase.database().ref(f.settings().baseRef).update(doAction.var[guid].results,function(n){n?t(n):e()})}catch(e){t(e)}})}function endAction(e){return f.debug("End action."),$q(function(t,n){doAction.var[guid].log.endedAt=getTime(),doAction.var[guid].log.duration=doAction.var[guid].log.endedAt-doAction.var[guid].log.startedAt+" milliseconds",doAction.var[guid].log._error=e||null,t()})}f.debug("flatte.do() called...");var getTime=function(){return(new Date).valueOf()},guid="doID"+f.dbKey(),placeIDs=function(e,t,n,a){function o(e,t,n){return $q(function(o){var r=!1;t.map(function(t,o){i.push($q(function(i){a+t===n&&(r=e[o]),i()}))}),$q.all(i).then(function(){o(r)}).catch(function(e){console.log(e)})})}var i=[],r=[];return n.map(function(n){i.push($q(function(a){t?o(e,t,n).then(function(e){e?r.push(e):r.push(n),a()}):(r.push(n),a())}))}),$q(function(e){$q.all(i).then(function(){e(r)}).catch(function(e){console.log(e)})})},commands={ID:function(e,t,n,a,o,i){return $q(function(e,t){e()})},saveValue:function(e,t,n,a,o,i){return $q(function(e,r){var u={};if(".doNothing"!==a&&"save"===o)if(n=angular.isObject(n)?n.join("/"):n,angular.isObject(a))if(a.filter){var s=a.hasOwnProperty("params")?a.params.split("|"):[];s.unshift(t),u[n]=$filter(a.filter).apply(this,s)}else u[n]=t;else u[n]=null===a||"$"===a?t:a;(function(e){var t=[],a={},o="",r="";return angular.forEach(e,function(e,a){"string"==typeof a?t.push($q(function(e){placeIDs(n.split("/"),i,a.split("/"),"#").then(function(t){o=t.join("/"),e()})})):o=a,"string"==typeof e?t.push($q(function(t){placeIDs(n.split("/"),i,e.split("/"),"#").then(function(e){r=e.join("/"),t()})})):r=e}),$q(function(e){$q.all(t).then(function(t){""!==o&&""!==r&&(a[o]=r),e(a)})})})(u).then(function(t){e(t)})})},deleteValue:function(e,t,n,a,o,i){return $q(function(e,r){var u={};"save"!==o&&(n=angular.isObject(n)?n.join("/"):n,".doNothing"!==a&&"delete"===o?u[n]="$"===a?t:null===a||"null"===a?null:a:"setNull"===o&&(u[n]=null)),function(e){var t=[],a={},o="",r="";return angular.forEach(e,function(e,a){"string"==typeof a?t.push($q(function(e){placeIDs(n.split("/"),i,a.split("/"),"#").then(function(t){o=t.join("/"),e()})})):o=a,"string"==typeof e?t.push($q(function(t){placeIDs(n.split("/"),i,e.split("/"),"#").then(function(e){r=e.join("/"),t()})})):r=e}),$q(function(e){$q.all(t).then(function(t){""!==o&&""!==r&&(a[o]=r),e(a)})})}(u).then(function(t){e(t)})})},copy:function(e,t,n,a,o,i){return $q(function(r,u){function s(t,a,o,r){var u=[];return u.push($q(function(u,s){placeIDs(n,i,t.split("/"),"#").then(function(t){"string"==typeof saveValue?placeIDs(n,i,o.saveValue.split("/"),"#").then(function(n){commands.saveValue(e,a,t.join("/"),n.join("/"),r,i).then(function(e){angular.extend(f,e),u()}).catch(function(e){return s(e),!1})}):commands.saveValue(e,a,t.join("/"),o.saveValue,r,i).then(function(e){angular.extend(f,e),u()}).catch(function(e){return s(e),!1})})})),u.push($q(function(u,s){placeIDs(n,i,t.split("/"),"#").then(function(t){"string"==typeof deleteValue?placeIDs(n,i,o.deleteValue.split("/"),"#").then(function(n){commands.deleteValue(e,a,t.join("/"),n.join("/"),r,i).then(function(e){angular.extend(f,e),u()}).catch(function(e){return s(e),!1})}):commands.deleteValue(e,a,t.join("/"),o.deleteValue,r,i).then(function(e){angular.extend(f,e),u()}).catch(function(e){return s(e),!1})})})),$q.all(u)}function c(e,t,n,a){var o=[];return("save"===a&&(null===n.saveValue||"$"===n.saveValue||"string"==typeof n.saveValue&&""===n.saveValue.trim())||"save"!==a&&(null===n.deleteValue||"$"===n.deleteValue||"string"==typeof n.deleteValue&&""===n.deleteValue.trim()))&&angular.isObject(t)?angular.forEach(t,function(t,i){o.push($q(function(o,r){n.saveValue=""!==n.saveValue.trim()?n.saveValue:"$",n.deleteValue=""!==n.deleteValue.trim()?n.deleteValue:"$",c(e+"/"+i,t,n,a).then(function(e){o(e)}).catch(function(e){return r(e),!1})}))}):o.push($q(function(o,i){s(e,t,n,a).then(function(e){o(e)}).catch(function(e){return i(e),!1})})),$q.all(o)}if(!a)return r(),!1;var f={},l=[];a&&a.map(function(e){l.push($q(function(n,a){c(e.path,t,e,o).then(function(e){n()}).catch(function(e){return a(e),!1})}))}),$q.all(l).then(function(e){r(f)}).catch(function(e){return u(e),!1})})},externalEffect:function(e,t,n,a,o,i){return $q(function(r,u){function s(e){var t=[],a={path:"",if:{key:"",value:""},save:{key:"",value:""},delete:{key:"",value:""}};return e.hasOwnProperty("path")||(e.path=""),t.push($q(function(t){placeIDs(n,i,e.path.split("/"),"#").then(function(e){a.path=e.join("/"),t()})})),e.hasOwnProperty("if")?(e.if.hasOwnProperty("key")||(e.if.key=""),e.if.hasOwnProperty("value")||(e.if.value="")):e.if={key:"",value:""},t.push($q(function(t){placeIDs(n,i,e.if.key.split("/"),"#").then(function(e){a.if.key=e.join("/"),t()})})),t.push($q(function(t){placeIDs(n,i,e.if.value.split("/"),"#").then(function(e){a.if.value=e.join("/"),t()})})),e.hasOwnProperty("save")?(e.save.hasOwnProperty("key")||(e.save.key=""),e.save.hasOwnProperty("value")||(e.save.value="")):e.if={key:"",value:""},t.push($q(function(t){placeIDs(n,i,e.save.key.split("/"),"#").then(function(e){a.save.key=e.join("/"),t()})})),t.push($q(function(t){placeIDs(n,i,e.save.value.split("/"),"#").then(function(e){a.save.value=e.join("/"),t()})})),e.hasOwnProperty("delete")?(e.delete.hasOwnProperty("key")||(e.delete.key=""),e.delete.hasOwnProperty("value")||(e.delete.value="")):e.delete={key:"",value:""},t.push($q(function(t){placeIDs(n,i,e.delete.key.split("/"),"#").then(function(e){a.delete.key=e.join("/"),t()})})),t.push($q(function(t){placeIDs(n,i,e.delete.value.split("/"),"#").then(function(e){a.delete.value=e.join("/"),t()})})),$q(function(e,n){$q.all(t).then(function(){var t,n;"string"==typeof a.if.value?(n=a.if.value.replace(/\([^\)]*\)/g,"()")?a.if.value.replace(/\([^\)]*\)/g,"()").replace("()",""):a.if.value,n&&(t=a.if.value.match(/\([^\)]*\)/g)),t&&(t=t[0].replace("(","").replace(")",""))):n=a.if.value,a.if.value=f.settings().predefined.hasOwnProperty(n)?"function"==typeof f.settings().predefined[n]?f.settings().predefined[n](t):f.settings().predefined[a.if.value]:a.if.value,e(a)})})}function c(t,n,a,o){var r=[];return".doNothing"!==a.save.value&&("save"===o?r.push($q(function(r,u){commands.saveValue(e,t,(n+"/"+a.save.key).split("/"),a.save.value,o,i).then(function(e){angular.equals(t,e)||angular.extend(d,e),r()}).catch(function(e){return u(e),!1})})):r.push($q(function(r,u){commands.deleteValue(e,t,(n+"/"+a.delete.key).split("/"),a.delete.value,o,i).then(function(e){angular.equals(t,e)||angular.extend(d,e),r()}).catch(function(e){return u(e),!1})}))),$q.all(r)}function l(e,t,n,a){var o=[];return angular.forEach(e,function(e,i){o.push($q(function(e,o){c(t,n.path+"/"+i,n,a).then(function(){e()}).catch(function(e){return o(e),!1})}))}),$q.all(o)}if(!a)return r(),!1;var d={},h=[];angular.forEach(a,function(e){h.push($q(function(n,a){s(e).then(function(e){firebase.database().ref(f.settings().baseRef+"/"+e.path).orderByChild(e.if.key).equalTo(e.if.value).once("value",function(i){l(i.val(),t,e,o).then(function(e){n()}).catch(function(e){return a(e),!1})},function(e){a(e)})})}))}),$q.all(h).then(function(e){r(d)})})},function:function(ref,data,path,options,action,manifestPath){function replace(e){var t=[],n={},a="",o="";return angular.forEach(e,function(e,n){"string"==typeof n&&t.push($q(function(e){placeIDs(path,manifestPath,n.split("/"),"#").then(function(t){a=t.join("/"),e()})})),"string"==typeof e&&t.push($q(function(t){placeIDs(path,manifestPath,e.split("/"),"#").then(function(e){o=e.join("/"),t()})}))}),$q(function(e){$q.all(t).then(function(t){""!==a&&""!==o&&(n[a]=o),e(n)})})}return $q(function(resolve,reject){var $function=function(){return $q.when()};if("function"==typeof options)$function=options;else if("string"==typeof options)try{var res={};eval("$function = "+options)}catch(e){return reject(e),!1}options?$function(f,$q,ref,data,path,action,manifestPath).then(function(e){resolve(e)}).catch(function(e){return reject(e),!1}):resolve()})}},tasks=[createAction,createObjects,loopData,perform,createFinalResults,update,endAction];return progress&&(progress[guid]={total:8}),progress&&(progress[guid].count=0),progress&&(progress[guid].message="Pending..."),$q(function(e,t){f.serial(tasks).then(function(){f.settings().debug?e({results:doAction.var[guid].results||"No save result generated !..",manifestInfections:doAction.var[guid].appliedManifest}):(delete doAction.var[guid],e()),f.debug("flatte.do() ended with success"),progress&&progress[guid].count++,progress&&(progress[guid].message="End action...")}).catch(function(e){endAction(e),t(e),f.debug("flatte.do() ended with error")})})}var f={checkConnection:checkConnection,settings:settings,debug:debug,serial:serial,db:firebase.database(),dbref:firebase.database().ref(),dbTime:function(){return firebase.database.ServerValue.TIMESTAMP},dbKey:function(){return firebase.database().ref().push().key},cleanData:function(e){return JSON.parse(JSON.serialize(e))},do:doAction};return f.settings({debug:!1,baseRef:"/",con:null,manifest:{},predefined:{".true":!0,".false":!1,".null":null,".timestamp":firebase.database.ServerValue.TIMESTAMP}},!0),doAction.var={},doAction.getDebug=function(){return this.var},doAction.clearDebug=function(){this.var={}},f}angular.module("mx.flatte",[]).factory("flatte",flatte),flatte.$inject=["$q","$filter","$timeout"]}();