partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

PartKeepr.js (23617B)


      1 Ext.namespace('PartKeepr');
      2 
      3 PartKeepr.application = null;
      4 
      5 Ext.application({
      6     name: 'PartKeepr',
      7     loginManager: null,
      8 
      9     init: function ()
     10     {
     11 
     12 
     13     },
     14     launch: function ()
     15     {
     16         Ext.setGlyphFontFamily('FontAwesome');
     17         Ext.get("loader-wrapper").hide();
     18         Ext.setLocale('en_US');
     19 
     20         this.createLayout();
     21 
     22         PartKeepr.application = this;
     23 
     24         // Set static data of the server
     25         PartKeepr.setMaxUploadSize(window.parameters.maxUploadSize);
     26         PartKeepr.setAvailableImageFormats(window.parameters.availableImageFormats);
     27         PartKeepr.setOctoPartAvailable(window.parameters.isOctoPartAvailable);
     28 
     29         var authenticationProvider = Ext.create(window.parameters.authentication_provider);
     30         PartKeepr.Auth.AuthenticationProvider.setAuthenticationProvider(authenticationProvider);
     31 
     32         this.control({
     33             'MenuBar menuitem': {
     34                 click: this.onAppMenuClick,
     35                 scope: this
     36             }
     37         });
     38 
     39         var config = {};
     40 
     41         if (window.parameters.autoLoginUsername) {
     42             config.autoLogin = true;
     43             config.autoLoginUsername = window.parameters.autoLoginUsername;
     44             config.autoLoginPassword = window.parameters.autoLoginPassword;
     45         }
     46 
     47         this.loginManager = Ext.create("PartKeepr.Auth.LoginManager", config);
     48         this.loginManager.on("login", this.onLogin, this);
     49         this.loginManager.on("logout", this.onLogout, this);
     50         this.loginManager.login();
     51     },
     52     onAppMenuClick: function (item)
     53     {
     54         if (typeof item.target === "function") {
     55             this.openAppItem(item.target["$className"]);
     56         }
     57 
     58         if (typeof(item.theme) === "string") {
     59             this.switchTheme(item.theme);
     60         }
     61     },
     62     openAppItem: function (target)
     63     {
     64         targetClass = Ext.ClassManager.get(target);
     65 
     66         var config = {
     67             title: targetClass.title,
     68             closable: targetClass.closable,
     69             iconCls: targetClass.iconCls
     70         };
     71 
     72         var j = Ext.create(target, config);
     73 
     74         if (targetClass.superclass["$className"] == "PartKeepr.Actions.BaseAction") {
     75             j.execute();
     76         } else {
     77             PartKeepr.getApplication().addItem(j);
     78             j.show();
     79         }
     80     },
     81     getParameter: function (parameter)
     82     {
     83         if (window.parameters[parameter] !== undefined) {
     84             return window.parameters[parameter];
     85         }
     86     },
     87     getLoginManager: function ()
     88     {
     89         return this.loginManager;
     90     },
     91     getPartManager: function ()
     92     {
     93         return this.partManager;
     94     },
     95     /**
     96      * Handles the login function. Initializes the part manager window,
     97      * enables the menu bar and creates the stores+loads them.
     98      */
     99     onLogin: function ()
    100     {
    101         this.createGlobalStores();
    102 
    103         var initialUserPreferences = Ext.decode(this.getLoginManager().getUser().get("initialUserPreferences"));
    104 
    105         var records = this.getUserPreferenceStore().getProxy().getReader().read(initialUserPreferences);
    106 
    107         this.getUserPreferenceStore().loadRecords(records.records);
    108 
    109         var preferredTheme = this.getUserPreference("partkeepr.user.theme", null);
    110 
    111         this.createPartManager();
    112 
    113         this.menuBar.enable();
    114 
    115         this.doSystemStatusCheck();
    116 
    117         this.unacknowledgedNoticesTask = Ext.TaskManager.start({
    118             run: this.doUnacknowledgedNoticesCheck,
    119             scope: this,
    120             interval: 100000
    121         });
    122 
    123         this.displayTipWindowTask = new Ext.util.DelayedTask(this.displayTipOfTheDayWindow, this);
    124         this.displayTipWindowTask.delay(100);
    125 
    126         if (window.parameters.motd) {
    127             this.displayMOTD();
    128         }
    129 
    130         this.getStatusbar().setConnected();
    131 
    132         if (preferredTheme !== null && preferredTheme !== window.theme) {
    133             this.switchTheme(preferredTheme);
    134         }
    135 
    136     },
    137     onLogout: function ()
    138     {
    139         this.menuBar.disable();
    140         this.centerPanel.removeAll(true);
    141         this.getStatusbar().setDisconnected();
    142 
    143         Ext.TaskManager.stop(this.unacknowledgedNoticesTask);
    144     },
    145     /**
    146      * Re-creates the part manager. This is usually called when the "compactLayout" configuration option has been
    147      * changed.
    148      *
    149      * @param none
    150      * @return nothing
    151      */
    152     recreatePartManager: function ()
    153     {
    154         this.centerPanel.remove(this.partManager);
    155         this.getPartManager().destroy();
    156 
    157         this.createPartManager();
    158     },
    159     /**
    160      * Creates the part manager. While this is usually only done after login, it can also happen when the user changes
    161      * the "compact" preference.
    162      */
    163     createPartManager: function ()
    164     {
    165         this.partManager = Ext.create("PartKeepr.PartManager", {
    166             title: i18n("Part Manager"),
    167             compactLayout: PartKeepr.getApplication().getUserPreference("partkeepr.partmanager.compactlayout", false),
    168             iconCls: 'web-icon brick',
    169             closable: false
    170         });
    171 
    172         this.centerPanel.insert(0, this.partManager);
    173     },
    174     /**
    175      * Sets the initial user preferences, which are applied into the userPreferenceStore after login.
    176      */
    177     setInitialUserPreferences: function (obj)
    178     {
    179         PartKeepr.initialUserPreferences = obj;
    180     },
    181     /**
    182      * Displays the tip of the day window.
    183      *
    184      * This method checks if the user has disabled tips, and if so, this method
    185      * avoids showing the window.
    186      */
    187     displayTipOfTheDayWindow: function ()
    188     {
    189         if (!Ext.data.StoreManager.lookup('TipOfTheDayStore') || !Ext.data.StoreManager.lookup(
    190                 'TipOfTheDayStore').isLoaded() || !Ext.data.StoreManager.lookup(
    191                 'TipOfTheDayHistoryStore') || !Ext.data.StoreManager.lookup(
    192                 'TipOfTheDayHistoryStore').isLoaded() || !this.getUserPreferenceStore().isLoaded()
    193         ) {
    194             this.displayTipWindowTask.delay(100);
    195             return;
    196         }
    197 
    198         if (PartKeepr.getApplication().getUserPreference("partkeepr.tipoftheday.showtips") !== false) {
    199             var j = Ext.create("PartKeepr.TipOfTheDayWindow");
    200 
    201             if (j.hasTips()) {
    202                 j.show();
    203             }
    204         }
    205     },
    206     /**
    207      * Displays a message-of-the-day
    208      */
    209     displayMOTD: function ()
    210     {
    211         Ext.MessageBox.alert(i18n("Message of the day"), window.parameters.motd);
    212     },
    213     /**
    214      * Does a schema status call against the PartKeepr installation, in order to verify if the schema is up-to-date.
    215      *
    216      * @param none
    217      * @return nothing
    218      */
    219     doSystemStatusCheck: function ()
    220     {
    221         var call = new PartKeepr.ServiceCall("api", "system_status");
    222         call.setHandler(Ext.bind(this.onSystemStatusCheck, this));
    223         call.doCall();
    224     },
    225     /**
    226      * Handler for the schema check
    227      * @param data The data returned from the server
    228      */
    229     onSystemStatusCheck: function (data)
    230     {
    231         if (data.schemaStatus !== "complete") {
    232             alert(i18n("Your database schema is not up-to-date! Please re-run setup immediately!"));
    233         }
    234 
    235         if (data.inactiveCronjobCount > 0) {
    236             alert(i18n("The following cronjobs aren't running:") + "\n\n" + data.inactiveCronjobs.join("\n"));
    237         }
    238     },
    239     /*
    240      * Checks for unacknowledged system notices. Triggers a service call against the server.
    241      * 
    242      * Checks if a session is active; otherwise, nothing will happen.
    243      * 
    244      * @param none
    245      * @return nothing
    246      */
    247     doUnacknowledgedNoticesCheck: function ()
    248     {
    249         this.systemNoticeStore.load({
    250             scope: this,
    251             callback: this.onUnacknowledgedNoticesCheck
    252         });
    253     },
    254     /**
    255      * Handler for the unacknowledged system notices check
    256      * @param data The data returned from the server
    257      */
    258     onUnacknowledgedNoticesCheck: function ()
    259     {
    260         if (this.systemNoticeStore.count() > 0) {
    261             this.statusBar.systemNoticeButton.show();
    262         } else {
    263             this.statusBar.systemNoticeButton.hide();
    264         }
    265     },
    266     createGlobalStores: function ()
    267     {
    268         this.footprintStore = Ext.create("Ext.data.Store",
    269             {
    270                 model: 'PartKeepr.FootprintBundle.Entity.Footprint',
    271                 pageSize: 99999999,
    272                 autoLoad: true
    273             });
    274 
    275         this.siPrefixStore = Ext.create("Ext.data.Store",
    276             {
    277                 model: 'PartKeepr.SiPrefixBundle.Entity.SiPrefix',
    278                 pageSize: 99999999,
    279                 autoLoad: true
    280             });
    281 
    282         this.currencyStore = Ext.create("PartKeepr.Data.Store.CurrencyStore", {
    283             autoLoad: true
    284         });
    285 
    286         this.distributorStore = Ext.create("Ext.data.Store",
    287             {
    288                 model: 'PartKeepr.DistributorBundle.Entity.Distributor',
    289                 pageSize: 99999999,
    290                 autoLoad: true
    291             });
    292 
    293         this.manufacturerStore = Ext.create("Ext.data.Store",
    294             {
    295                 model: 'PartKeepr.ManufacturerBundle.Entity.Manufacturer',
    296                 pageSize: 99999999,
    297                 autoLoad: true
    298             });
    299 
    300         this.partUnitStore = Ext.create("Ext.data.Store",
    301             {
    302                 model: 'PartKeepr.PartBundle.Entity.PartMeasurementUnit',
    303                 pageSize: 99999999,
    304                 autoLoad: true
    305             });
    306 
    307         this.unitStore = Ext.create("Ext.data.Store",
    308             {
    309                 model: 'PartKeepr.UnitBundle.Entity.Unit',
    310                 pageSize: 99999999,
    311                 autoLoad: true
    312             });
    313 
    314         this.userStore = Ext.create("Ext.data.Store",
    315             {
    316                 model: 'PartKeepr.AuthBundle.Entity.User',
    317                 pageSize: 99999999,
    318                 autoLoad: true
    319             });
    320 
    321         this.userPreferenceStore = Ext.create("PartKeepr.data.store.UserPreferenceStore",
    322             {
    323                 model: 'PartKeepr.AuthBundle.Entity.UserPreference',
    324                 autoLoad: false
    325             });
    326 
    327         this.barcodeScannerManager = Ext.create("PartKeepr.BarcodeScanner.Manager");
    328 
    329         this.systemPreferenceStore = Ext.create("PartKeepr.data.store.SystemPreferenceStore",
    330             {
    331                 model: 'PartKeepr.SystemPreferenceBundle.Entity.SystemPreference',
    332                 autoLoad: true,
    333                 listeners: {
    334                     scope: this,
    335                     "load": function ()
    336                     {
    337                         this.barcodeScannerManager.registerBarcodeScannerHotkey();
    338                     }
    339                 }
    340             });
    341 
    342         this.tipOfTheDayStore = Ext.create("PartKeepr.data.store.TipOfTheDayStore");
    343         this.tipOfTheDayHistoryStore = Ext.create("PartKeepr.data.store.TipOfTheDayHistoryStore");
    344         this.systemNoticeStore = Ext.create("PartKeepr.data.store.SystemNoticeStore");
    345 
    346     },
    347     getBarcodeScannerManager: function ()
    348     {
    349         return this.barcodeScannerManager;
    350 
    351     },
    352     storeLoaded: function (store)
    353     {
    354         store._loaded = true;
    355     },
    356     setAdmin: function (admin)
    357     {
    358         this.admin = admin;
    359     },
    360     isAdmin: function ()
    361     {
    362         return this.admin;
    363     },
    364     getSystemPreferenceStore: function ()
    365     {
    366         return this.systemPreferenceStore;
    367     },
    368     /**
    369      * Queries for a specific system preference. Returns either the value or a default value if
    370      * the preference was not found.
    371      * @param key The key to query
    372      * @param defaultValue A default value to return (optional)
    373      * @returns the key value, or defaultValue if preference key was not found
    374      */
    375     getSystemPreference: function (key, defaultValue)
    376     {
    377         if (this.systemPreferenceStore === undefined) {
    378             return defaultValue;
    379         }
    380         var record = this.systemPreferenceStore.findRecord("preferenceKey", key);
    381 
    382         if (record) {
    383             var value = record.get("preferenceValue");
    384             var decodedValue = Ext.decode(value, true);
    385 
    386             if (decodedValue === null) {
    387                 return value;
    388             } else {
    389                 return decodedValue;
    390             }
    391         } else {
    392             return (typeof defaultValue == "undefined") ? null : defaultValue;
    393         }
    394     },
    395     /**
    396      * Sets a specific system preference. Directly commits the change to the server.
    397      *
    398      * @param key The key to set
    399      * @param value The value to set
    400      */
    401     setSystemPreference: function (key, value)
    402     {
    403         var record = this.systemPreferenceStore.findRecord("preferenceKey", key);
    404         value = Ext.encode(value);
    405 
    406         if (record) {
    407             if (record.get("preferenceValue") != value) {
    408                 record.set("preferenceValue", value);
    409                 record.save();
    410             }
    411         } else {
    412             var j = new PartKeepr.SystemPreferenceBundle.Entity.SystemPreference();
    413             j.set("preferenceKey", key);
    414             j.set("preferenceValue", value);
    415             j.save();
    416             this.systemPreferenceStore.add(j);
    417         }
    418     },
    419     /**
    420      * Queries for a specific user preference. Returns either the value or a default value if
    421      * the preference was not found.
    422      * @param key The key to query
    423      * @param defaultValue A default value to return (optional)
    424      * @returns the key value, or defaultValue if preference key was not found
    425      */
    426     getUserPreference: function (key, defaultValue)
    427     {
    428         var record = this.userPreferenceStore.findRecord("preferenceKey", key);
    429 
    430         if (record) {
    431             var value = record.get("preferenceValue");
    432             var decodedValue = Ext.decode(value, true);
    433 
    434             if (decodedValue === null) {
    435                 return value;
    436             } else {
    437                 return decodedValue;
    438             }
    439         } else {
    440             return (typeof defaultValue == "undefined") ? null : defaultValue;
    441         }
    442     },
    443     /**
    444      * Sets a specific user preference. Directly commits the change to the server.
    445      *
    446      * @param key The key to set
    447      * @param value The value to set
    448      */
    449     setUserPreference: function (key, value)
    450     {
    451         var record = this.userPreferenceStore.findRecord("preferenceKey", key);
    452         value = Ext.encode(value);
    453 
    454         if (record) {
    455             if (record.get("preferenceValue") != value) {
    456                 record.set("preferenceValue", value);
    457                 record.save();
    458             }
    459         } else {
    460             var j = new PartKeepr.AuthBundle.Entity.UserPreference();
    461             j.set("preferenceKey", key);
    462             j.set("preferenceValue", value);
    463             j.save();
    464             this.userPreferenceStore.add(j);
    465         }
    466     },
    467     getUserPreferenceStore: function ()
    468     {
    469         return this.userPreferenceStore;
    470     },
    471     getUnitStore: function ()
    472     {
    473         return this.unitStore;
    474     },
    475     getPartUnitStore: function ()
    476     {
    477         return this.partUnitStore;
    478     },
    479     getFootprintStore: function ()
    480     {
    481         return this.footprintStore;
    482     },
    483     getManufacturerStore: function ()
    484     {
    485         return this.manufacturerStore;
    486     },
    487     getDistributorStore: function ()
    488     {
    489         return this.distributorStore;
    490     },
    491     getCurrencyStore: function ()
    492     {
    493         return this.currencyStore;
    494     },
    495     getDefaultPartUnit: function ()
    496     {
    497         return this.partUnitStore.findRecord("default", true);
    498     },
    499     getUserStore: function ()
    500     {
    501         return this.userStore;
    502     },
    503     getSiPrefixStore: function ()
    504     {
    505         return this.siPrefixStore;
    506     },
    507     uploadFileFromURL: function (url, description, callback, scope)
    508     {
    509         var uploadURL = PartKeepr.getBasePath() + "/api/temp_uploaded_files/upload";
    510 
    511         var options = {
    512             url: uploadURL,
    513             method: 'POST',
    514             params: {
    515                 description: description,
    516                 url: url
    517             },
    518             callback: callback,
    519             scope: scope
    520         };
    521 
    522         Ext.Ajax.request(options);
    523     },
    524     /**
    525      * Converts the Character "micro" (µ, available on german keyboards via AltGr+m) to the Character "Mu" (μ).
    526      *
    527      *  The standard for Si-Prefixes defines that the "Mu"-character should be used instead of the "micro" character.
    528      *
    529      *  Wikipedia Entry for the "Micro" Si Prefix: http://en.wikipedia.org/wiki/Micro-
    530      *
    531      */
    532     convertMicroToMu: function (value)
    533     {
    534         /**
    535          * Since the Si-Prefix for "micro" is μ, but keyboard have "µ" on it
    536          * (note: both chars might look identical, depending on your font), we need
    537          * to convert "µ" (on the keyboard, Unicode U+00B5) to the Mu (U+03BC).
    538          */
    539 
    540         return str_replace("µ", "μ", value);
    541     },
    542     /**
    543      * Creates the main view of PartKeepr.
    544      */
    545     createLayout: function ()
    546     {
    547         this.statusBar = Ext.create("PartKeepr.Statusbar");
    548 
    549         this.messageLog = this.createMessageLog();
    550 
    551         this.centerPanel = Ext.create("Ext.tab.Panel", {
    552             xtype: 'tabpanel',
    553             border: false,
    554             region: 'center',
    555             bodyStyle: 'background:#DBDBDB',
    556             plugins: Ext.create('Ext.ux.TabCloseMenu')
    557 
    558         });
    559 
    560 
    561         this.menuBar = Ext.create("PartKeepr.MenuBar");
    562 
    563         this.menuBar.disable();
    564         this.viewPort = Ext.create('Ext.container.Viewport', {
    565             layout: 'fit',
    566             items: [
    567                 {
    568                     xtype: 'panel',
    569                     border: false,
    570                     layout: 'border',
    571                     items: [
    572                         this.centerPanel,
    573                         this.messageLog
    574                     ],
    575                     bbar: this.statusBar,
    576                     tbar: this.menuBar
    577                 }
    578             ]
    579 
    580         });
    581     },
    582     addItem: function (item)
    583     {
    584         this.centerPanel.add(item);
    585     },
    586     createMessageLog: function ()
    587     {
    588         return Ext.create("PartKeepr.MessageLog", {
    589             height: 200,
    590             hidden: true,
    591             split: true,
    592             title: i18n("Message Log"),
    593             titleCollapse: true,
    594             collapsible: true,
    595             region: 'south',
    596             listeners: {
    597                 beforecollapse: Ext.bind(
    598                     function (obj)
    599                     {
    600                         this.hideMessageLog();
    601                         return false;
    602                     },
    603                     this)
    604             }
    605         });
    606     },
    607     log: function (message)
    608     {
    609         this.logMessage(message, "none");
    610     },
    611     logMessage: function (message, severity)
    612     {
    613         if (message != i18n("Ready.")) {
    614             var r = Ext.ModelManager.create({
    615                 message: message,
    616                 severity: severity,
    617                 date: new Date()
    618             }, 'PartKeepr.Message');
    619 
    620             this.messageLog.getStore().add(r);
    621         }
    622     },
    623     hideMessageLog: function ()
    624     {
    625         this.messageLog.hide();
    626     },
    627     showMessageLog: function ()
    628     {
    629         this.messageLog.show();
    630     },
    631     toggleMessageLog: function ()
    632     {
    633         if (this.messageLog.isHidden()) {
    634             this.showMessageLog();
    635         } else {
    636             this.hideMessageLog();
    637         }
    638 
    639     },
    640     getStatusbar: function ()
    641     {
    642         return this.statusBar;
    643     },
    644     /**
    645      * Sets the username. This should only be called from the login dialog.
    646      *
    647      * Also updates the statusbar to reflect the username.
    648      *
    649      * @param {string} username The username to set
    650      */
    651     setUsername: function (username)
    652     {
    653         this.username = username;
    654         this.getStatusbar().setCurrentUser(username);
    655     },
    656     /**
    657      * Returns the current username
    658      * @returns {string}
    659      */
    660     getUsername: function ()
    661     {
    662         return this.username;
    663     },
    664     formatCurrency: function (value, code)
    665     {
    666         var format = Ext.util.Format;
    667         format.currencyPrecision = PartKeepr.getApplication().getUserPreference(
    668             "partkeepr.formatting.currency.numdecimals", 2);
    669 
    670         format.currencySign = PartKeepr.getApplication().getUserPreference("partkeepr.formatting.currency.symbol", "€");
    671 
    672         if (code !== null) {
    673             var currency = PartKeepr.getApplication().getCurrencyStore().findRecord("code", code, 0, false, false,
    674                 true);
    675 
    676             if (currency !== null) {
    677                 format.currencySign = currency.get("symbol");
    678             }
    679         }
    680 
    681         format.currencyAtEnd = PartKeepr.getApplication().getUserPreference(
    682             "partkeepr.formatting.currency.currencySymbolAtEnd", true);
    683 
    684         if (PartKeepr.getApplication().getUserPreference("partkeepr.formatting.currency.thousandsSeparator",
    685                 true) === true) {
    686             // @todo This is hard-coded for now
    687             format.thousandSeparator = ",";
    688         } else {
    689             format.thousandSeparator = "";
    690         }
    691 
    692         return format.currency(value);
    693     },
    694     switchTheme: function (theme)
    695     {
    696         if (window.themes[theme]) {
    697             window.theme = theme;
    698             this.setUserPreference("partkeepr.user.theme", theme);
    699             this.menuBar.selectTheme(theme);
    700             Ext.util.CSS.swapStyleSheet("theme", window.themes[theme].themeUri);
    701             Ext.util.CSS.swapStyleSheet("themeUx", window.themes[theme].themeUxUri);
    702 
    703             Ext.get("loader-wrapper").show();
    704             Ext.get("loader-message").setHtml(i18n("Applying theme…"));
    705 
    706 
    707             Ext.defer(this.updateThemeLayout, 1000, this);
    708         }
    709     },
    710     updateThemeLayout: function ()
    711     {
    712         Ext.get("loader-wrapper").hide();
    713 
    714         Ext.defer(this.refreshLayout, 100, this);
    715     },
    716     refreshLayout: function () {
    717         this.viewPort.updateLayout();
    718     }
    719 });
    720 
    721 PartKeepr.getSession = function ()
    722 {
    723     alert("This should not be called.");
    724     return "hli2ong0ktnise68p9f5nu6nk1";
    725 };
    726 
    727 PartKeepr.log = function (message)
    728 {
    729     PartKeepr.getApplication().log(message);
    730 };
    731 
    732 /**
    733  * <p>This static method returns the instance of the application.</p>
    734  * @return {PartKeepr} The application
    735  */
    736 PartKeepr.getApplication = function ()
    737 {
    738     return PartKeepr.application;
    739 };
    740 
    741 PartKeepr.getBasePath = function ()
    742 {
    743     var href = document.getElementsByTagName('base')[0].href;
    744 
    745 
    746     if (href.substr(-2) === '//') {
    747         return href.substr(0, href.length - 2);
    748     }
    749 
    750     if (href.substr(-1) === '/') {
    751         return href.substr(0, href.length - 1);
    752     }
    753 
    754     return href;
    755 };
    756 
    757 PartKeepr.getImagePath = function ()
    758 {
    759     return "image.php";
    760 };
    761 
    762 PartKeepr.setMaxUploadSize = function (size)
    763 {
    764     PartKeepr.maxUploadSize = size;
    765 };
    766 
    767 PartKeepr.getMaxUploadSize = function ()
    768 {
    769     return PartKeepr.maxUploadSize;
    770 };
    771 
    772 PartKeepr.setOctoPartAvailable = function (octoPartAvailable)
    773 {
    774     PartKeepr.octoPartAvailable = octoPartAvailable;
    775 };
    776 
    777 PartKeepr.isOctoPartAvailable = function ()
    778 {
    779     return PartKeepr.octoPartAvailable;
    780 };
    781 
    782 PartKeepr.bytesToSize = function (bytes)
    783 {
    784     var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
    785     if (bytes === 0) {
    786         return '0 Bytes';
    787     }
    788     var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
    789     return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
    790 };
    791 
    792 PartKeepr.setAvailableImageFormats = function (formats)
    793 {
    794     PartKeepr.imageFormats = formats;
    795 };
    796 
    797 PartKeepr.getAvailableImageFormats = function ()
    798 {
    799     return PartKeepr.imageFormats;
    800 };
    801 
    802 PartKeepr.serializeRecords = function (records)
    803 {
    804     var finalData = [];
    805 
    806     for (var i = 0; i < records.length; i++) {
    807         finalData.push(records[i].data);
    808     }
    809 
    810     return finalData;
    811 };