<commit_before>/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, newcap: true */
/*global window, $, Backbone, document, arangoCollection,arangoHelper,dashboardView,arangoDatabase*/

(function() {
  "use strict";

  window.Router = Backbone.Router.extend({
    routes: {
      ""                                    : "dashboard",
      "dashboard"                           : "dashboard",
      "collection/:colid"                   : "collection",
      "collections"                         : "collections",
      "collectionInfo/:colid"               : "collectionInfo",
      "new"                                 : "newCollection",
      "login"                               : "login",
      "collection/:colid/documents/:pageid" : "documents",
      "collection/:colid/:docid"            : "document",
      "collection/:colid/:docid/source"     : "source",
      "shell"                               : "shell",
      "query"                               : "query",
      "logs"                                : "logs",
      "api"                                 : "api",
      "databases"                           : "databases",
      "application/installed/:key"          : "applicationEdit",
      "application/available/:key"          : "applicationInstall",
      "applications/installed"              : "applicationsInstalled",
      "applications/available"              : "applicationsAvailable",
      "applications"                        : "applications",
      "application/documentation/:key"      : "appDocumentation",
      "graph"                               : "graph",
      "graphManagement"                     : "graphManagement",
      "graphManagement/add"                 : "graphAddNew",
      "graphManagement/delete/:name"        : "graphDelete",
      "userManagement"                      : "userManagement",
      "userProfile"                         : "userProfile"
    },

    initialize: function () {
      this.graphs = new window.GraphCollection();
      this.notificationList = new window.NotificationCollection();

      window.currentDB = new window.CurrentDatabase();
      window.currentDB.fetch({
        async: false
      });

      window.userCollection = new window.ArangoUsers();

      window.arangoDatabase = new window.ArangoDatabase();

      window.arangoCollectionsStore = new window.arangoCollections();
      window.arangoDocumentsStore = new window.arangoDocuments();
      window.arangoDocumentStore = new window.arangoDocument();

      window.collectionsView = new window.CollectionsView({
        collection: window.arangoCollectionsStore
      });
      window.arangoCollectionsStore.fetch();
      window.documentsView = new window.DocumentsView();
      window.documentView = new window.DocumentView();
      window.documentSourceView = new window.DocumentSourceView();
      window.arangoLogsStore = new window.ArangoLogs();
      window.arangoLogsStore.fetch({
        success: function () {
          window.logsView = new window.LogsView({
            collection: window.arangoLogsStore
          });
        }
      });

      this.foxxList = new window.FoxxCollection();

      this.footerView = new window.FooterView();
      this.naviView = new window.NavigationView({
        notificationCollection: this.notificationList
      });
      this.footerView.render();
      this.naviView.render();
      this.graphView = new window.GraphView({
        graphs: this.graphs,
        collection: window.arangoCollectionsStore
      });

      // this.initVersionCheck();

      var self = this;
      $(window).resize(function() {
        self.handleResize();
      });
      this.handleResize();
    },

/*
    initVersionCheck: function () {
      // this checks for version updates

      var self = this;
      var versionCheck = function () {
        $.ajax({
          async: true,
          crossDomain: true,
          dataType: "jsonp",
          url: "https://www.arangodb.org/repositories/versions.php?callback=parseVersions",
          success: function (json) {
            if (typeof json !== 'object') {
              return;
            }

            // turn our own version string into a version object
            var currentVersion = window.versionHelper.fromString(self.footerView.system.version);

            // get our mainline version
            var mainLine = window.versionHelper.toStringMainLine(currentVersion);

            var mainLines = Object.keys(json).sort(window.versionHelper.compareVersionStrings);
            var latestMainLine;
            mainLines.forEach(function (l) {
              if (json[l].stable) {
                if (window.versionHelper.compareVersionStrings(l, mainLine) > 0) {
                  latestMainLine = json[l];
                }
              }
            });

            var update;

            if (latestMainLine !== undefined &&
                Object.keys(latestMainLine.versions.length > 0) {
              var mainLineVersions = Object.keys(latestMainLine.versions);
              mainLineVersions = mainLineVersions.sort(window.versionHelper.compareVersionStrings);
              var latest = mainLineVersions[mainLineVersions.length - 1];

              update = {
                type: "major",
                version: latest,
                changes: latestMainLine.versions[latest].changes
              };
            }

            // check which stable mainline versions are available remotely
            if (update === undefined &&
                json.hasOwnProperty(mainLine) &&
                json[mainLine].stable &&
                json[mainLine].hasOwnProperty("versions") &&
                Object.keys(json[mainLine].versions).length > 0) {
              // sort by version numbers
              var mainLineVersions = Object.keys(json[mainLine].versions);
              mainLineVersions = mainLineVersions.sort(window.versionHelper.compareVersionStrings);
              var latest = mainLineVersions[mainLineVersions.length - 1];

              var result = window.versionHelper.compareVersions(
                currentVersion,
                window.versionHelper.fromString(latest)
              );
              if (result < 0) {
                update = {
                  type: "minor",
                  version: latest,
                  changes: json[mainLine].versions[latest].changes
                };
              }
            }

            if (update !== undefined) {
              var msg = "A newer version of ArangoDB (" + update.version +
                        ") has become available. You may want to check the " +
                        "changelog at " +
                        update.changes + "";
              arangoHelper.arangoNotification(msg, 15000);

            }
          },
          error: function () {
            // re-schedule the version check
            window.setTimeout(versionCheck, 60000);
          }
        });
      };

      window.setTimeout(versionCheck, 5000);
    },
*/

    logsAllowed: function () {
      return (window.databaseName === '_system');
    },

    checkUser: function () {
      if (window.userCollection.models.length === 0) {
        this.navigate("login", {trigger: true});
        return false;
      }
      return true;
    },

    login: function () {
      if (!this.loginView) {
        this.loginView = new window.loginView({
          collection: window.userCollection
        });
      }
      this.loginView.render();
      this.naviView.selectMenuItem('');
    },

    collections: function() {
      var naviView = this.naviView;
      window.arangoCollectionsStore.fetch({
        success: function () {
          window.collectionsView.render();
          naviView.selectMenuItem('collections-menu');
        }
      });
    },

    collection: function(colid) {
      if (!this.collectionView) {
        this.collectionView = new window.CollectionView();
      }
      this.collectionView.setColId(colid);
      this.collectionView.render();
      this.naviView.selectMenuItem('collections-menu');
    },
    collectionInfo: function(colid) {
      if (!this.collectionInfoView) {
        this.collectionInfoView = new window.CollectionInfoView();
      }
      this.collectionInfoView.setColId(colid);
      this.collectionInfoView.render();
      this.naviView.selectMenuItem('collections-menu');
    },
    newCollection: function() {
      if (!this.newCollectionView) {
        this.newCollectionView = new window.newCollectionView({});
      }
      this.newCollectionView.render();
      this.naviView.selectMenuItem('collections-menu');
    },

    documents: function(colid, pageid) {
      if (!window.documentsView) {
        window.documentsView.initTable(colid, pageid);
      }
      window.documentsView.collectionID = colid;
      var type = arangoHelper.collectionApiType(colid);
      window.documentsView.colid = colid;
      window.documentsView.pageid = pageid;
      window.documentsView.type = type;
      window.documentsView.render();
      window.arangoDocumentsStore.getDocuments(colid, pageid);
    },

    document: function(colid, docid) {
      if (!window.documentView) {
        window.documentView.initTable();
      }
      window.documentView.colid = colid;
      window.documentView.docid = docid;
      window.documentView.render();
      var type = arangoHelper.collectionApiType(colid);
      window.documentView.type = type;
      window.documentView.typeCheck(type);
    },

    source: function(colid, docid) {
      window.documentSourceView.render();
      window.documentSourceView.colid = colid;
      window.documentSourceView.docid = docid;
      var type = arangoHelper.collectionApiType(colid);
      window.documentSourceView.type = type;
      window.documentSourceView.typeCheck(type);
    },

    shell: function() {
      if (!this.shellView) {
        this.shellView = new window.shellView();
      }
      this.shellView.render();
      this.naviView.selectMenuItem('tools-menu');
    },

    query: function() {
      if (!this.queryView) {
        this.queryView = new window.queryView();
      }
      this.queryView.render();
      this.naviView.selectMenuItem('query-menu');
    },

    api: function() {
      if (!this.apiView) {
        this.apiView = new window.apiView();
      }
      this.apiView.render();
      this.naviView.selectMenuItem('tools-menu');
    },

    databases: function() {
      if (arangoHelper.databaseAllowed() === true) {
        if (!this.databaseView) {
          this.databaseView = new window.databaseView({
            collection: arangoDatabase
          });
        }
        this.databaseView.render();
        this.naviView.selectMenuItem('databases-menu');
      }
      else {
        this.navigate("#", {trigger: true});
        this.naviView.selectMenuItem('dashboard-menu');
        $('#databaseNavi').css('display','none');
        $('#databaseNaviSelect').css('display','none');
      }
    },

    logs: function() {
      if (! this.logsAllowed()) {
        this.navigate('', { trigger: true });
        return;
      }

      window.arangoLogsStore.fetch({
        success: function () {
          window.logsView.render();
          $('#logNav a[href="#all"]').tab('show');
          window.logsView.initLogTables();
          window.logsView.drawTable();
          $('#all-switch').click();
        }
      });
      this.naviView.selectMenuItem('tools-menu');
    },

    dashboard: function() {
      this.naviView.selectMenuItem('dashboard-menu');
      if (this.statisticsDescription === undefined) {
        this.statisticsDescription = new window.StatisticsDescription();
        this.statisticsDescription.fetch({
          async:false
        });
      }
      if (this.statistics === undefined) {
        this.statisticsCollection = new window.StatisticsCollection();
      }
      if (this.dashboardView === undefined) {
        this.dashboardView = new dashboardView({
          collection: this.statisticsCollection,
          description: this.statisticsDescription
        });
         }
        this.dashboardView.render();
    },

    graph: function() {
      var self = this;
      window.arangoCollectionsStore.fetch({
        success: function () {
          self.graphView.render();
          self.naviView.selectMenuItem('graphviewer-menu');
        }
      });
    },

    graphManagement: function() {
      if (!this.graphManagementView) {
        this.graphManagementView = new window.GraphManagementView({collection: this.graphs});
      }
      this.graphManagementView.render();
      this.naviView.selectMenuItem('graphviewer-menu');
    },

    graphAddNew: function() {
      if (!this.addNewGraphView) {
        this.addNewGraphView = new window.AddNewGraphView({
          collection: window.arangoCollectionsStore,
          graphs: this.graphs
        });
      }
      this.addNewGraphView.render();
      this.naviView.selectMenuItem('graphviewer-menu');
    },

    graphDelete: function(name) {
      if (!this.deleteGraphView) {
        this.deleteGraphView = new window.DeleteGraphView({
          collection: this.graphs
        });
      }
      this.deleteGraphView.render(name);
      this.naviView.selectMenuItem('graphviewer-menu');
    },

    applications: function() {
      if (this.applicationsView === undefined) {
        this.applicationsView = new window.ApplicationsView({
          collection: this.foxxList
        });
      }
      this.applicationsView.reload();
      this.naviView.selectMenuItem('applications-menu');
    },

    applicationsAvailable: function() {
      if (this.applicationsInstalledView === undefined) {
        this.applicationsInstalledView = new window.FoxxInstalledListView({
          collection: this.foxxList
        });
      }
      this.applicationsInstalledView.reload();
      this.naviView.selectMenuItem('applications-menu');
    },

    applicationsInstalled: function() {
      if (this.applicationsActiveView === undefined) {
        this.applicationsActiveView = new window.FoxxActiveListView({
          collection: this.foxxList
        });
      }
      this.applicationsActiveView.reload();
      this.naviView.selectMenuItem('applications-menu');
    },

    applicationEdit: function(appkey) {
      this.foxxList.fetch({
        async: false
      });
      var editAppView = new window.foxxEditView({model: this.foxxList.findWhere({_key: appkey})});
      editAppView.render();
    },

    applicationInstall: function(appkey) {
      this.foxxList.fetch({
        async: false
      });
      if (!this.installAppView) {
        this.installAppView = new window.foxxMountView({
          collection: this.foxxList
        });
      }
      this.installAppView.render(appkey);
    },

    appDocumentation: function(key) {
      var docuView = new window.AppDocumentationView({key: key});
      docuView.render();
      this.naviView.selectMenuItem('applications-menu');
    },

    handleSelectDatabase: function () {
      this.footerView.handleSelectDatabase();
    },

    handleResize: function () {
      var oldWidth = $('#content').width();
      var containerWidth = $(window).width() - 70;
      /*var spanWidth = 242;*/
      var spanWidth = 243;
      var divider = containerWidth / spanWidth;
      var roundDiv = parseInt(divider, 10);
      var newWidth = roundDiv*spanWidth -2;
      var marginWidth = ((containerWidth+30) - newWidth)/2;
      /*
      $('#content').width(newWidth)
      .css('margin-left', marginWidth)
      .css('margin-right', marginWidth);
      */
      // $('.footer-right p').css('margin-right', marginWidth + 20);
      // $('.footer-left p').css('margin-left', marginWidth + 20);
      if (newWidth !== oldWidth) {
        this.graphView.handleResize(newWidth);
      }
    },

    userManagement: function() {
      if (!this.userManagementView) {
        this.userManagementView = new window.userManagementView({
          collection: window.userCollection
        });
      }
      this.userManagementView.render();
      this.naviView.selectMenuItem('user-menu');
    },

    userProfile: function() {
      if (!this.userProfileView) {
        this.userProfileView = new window.userProfileView({
          collection: window.userCollection
        });
      }
      this.userProfileView.render();
      this.naviView.selectMenuItem('user-menu');
    }

  });

}());
<commit_msg>dbdropdown refresh fixed<commit_after>/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, newcap: true */
/*global window, $, Backbone, document, arangoCollection,arangoHelper,dashboardView,arangoDatabase*/

(function() {
  "use strict";

  window.Router = Backbone.Router.extend({
    routes: {
      ""                                    : "dashboard",
      "dashboard"                           : "dashboard",
      "collection/:colid"                   : "collection",
      "collections"                         : "collections",
      "collectionInfo/:colid"               : "collectionInfo",
      "new"                                 : "newCollection",
      "login"                               : "login",
      "collection/:colid/documents/:pageid" : "documents",
      "collection/:colid/:docid"            : "document",
      "collection/:colid/:docid/source"     : "source",
      "shell"                               : "shell",
      "query"                               : "query",
      "logs"                                : "logs",
      "api"                                 : "api",
      "databases"                           : "databases",
      "application/installed/:key"          : "applicationEdit",
      "application/available/:key"          : "applicationInstall",
      "applications/installed"              : "applicationsInstalled",
      "applications/available"              : "applicationsAvailable",
      "applications"                        : "applications",
      "application/documentation/:key"      : "appDocumentation",
      "graph"                               : "graph",
      "graphManagement"                     : "graphManagement",
      "graphManagement/add"                 : "graphAddNew",
      "graphManagement/delete/:name"        : "graphDelete",
      "userManagement"                      : "userManagement",
      "userProfile"                         : "userProfile"
    },

    initialize: function () {
      this.graphs = new window.GraphCollection();
      this.notificationList = new window.NotificationCollection();

      window.currentDB = new window.CurrentDatabase();
      window.currentDB.fetch({
        async: false
      });

      window.userCollection = new window.ArangoUsers();

      window.arangoDatabase = new window.ArangoDatabase();

      window.arangoCollectionsStore = new window.arangoCollections();
      window.arangoDocumentsStore = new window.arangoDocuments();
      window.arangoDocumentStore = new window.arangoDocument();

      window.collectionsView = new window.CollectionsView({
        collection: window.arangoCollectionsStore
      });
      window.arangoCollectionsStore.fetch();
      window.documentsView = new window.DocumentsView();
      window.documentView = new window.DocumentView();
      window.documentSourceView = new window.DocumentSourceView();
      window.arangoLogsStore = new window.ArangoLogs();
      window.arangoLogsStore.fetch({
        success: function () {
          window.logsView = new window.LogsView({
            collection: window.arangoLogsStore
          });
        }
      });

      this.foxxList = new window.FoxxCollection();

      this.footerView = new window.FooterView();
      this.naviView = new window.NavigationView({
        notificationCollection: this.notificationList
      });
      this.footerView.render();
      this.naviView.render();
      this.graphView = new window.GraphView({
        graphs: this.graphs,
        collection: window.arangoCollectionsStore
      });

      // this.initVersionCheck();

      var self = this;
      $(window).resize(function() {
        self.handleResize();
      });
      this.handleResize();
    },

/*
    initVersionCheck: function () {
      // this checks for version updates

      var self = this;
      var versionCheck = function () {
        $.ajax({
          async: true,
          crossDomain: true,
          dataType: "jsonp",
          url: "https://www.arangodb.org/repositories/versions.php?callback=parseVersions",
          success: function (json) {
            if (typeof json !== 'object') {
              return;
            }

            // turn our own version string into a version object
            var currentVersion = window.versionHelper.fromString(self.footerView.system.version);

            // get our mainline version
            var mainLine = window.versionHelper.toStringMainLine(currentVersion);

            var mainLines = Object.keys(json).sort(window.versionHelper.compareVersionStrings);
            var latestMainLine;
            mainLines.forEach(function (l) {
              if (json[l].stable) {
                if (window.versionHelper.compareVersionStrings(l, mainLine) > 0) {
                  latestMainLine = json[l];
                }
              }
            });

            var update;

            if (latestMainLine !== undefined &&
                Object.keys(latestMainLine.versions.length > 0) {
              var mainLineVersions = Object.keys(latestMainLine.versions);
              mainLineVersions = mainLineVersions.sort(window.versionHelper.compareVersionStrings);
              var latest = mainLineVersions[mainLineVersions.length - 1];

              update = {
                type: "major",
                version: latest,
                changes: latestMainLine.versions[latest].changes
              };
            }

            // check which stable mainline versions are available remotely
            if (update === undefined &&
                json.hasOwnProperty(mainLine) &&
                json[mainLine].stable &&
                json[mainLine].hasOwnProperty("versions") &&
                Object.keys(json[mainLine].versions).length > 0) {
              // sort by version numbers
              var mainLineVersions = Object.keys(json[mainLine].versions);
              mainLineVersions = mainLineVersions.sort(window.versionHelper.compareVersionStrings);
              var latest = mainLineVersions[mainLineVersions.length - 1];

              var result = window.versionHelper.compareVersions(
                currentVersion,
                window.versionHelper.fromString(latest)
              );
              if (result < 0) {
                update = {
                  type: "minor",
                  version: latest,
                  changes: json[mainLine].versions[latest].changes
                };
              }
            }

            if (update !== undefined) {
              var msg = "A newer version of ArangoDB (" + update.version +
                        ") has become available. You may want to check the " +
                        "changelog at " +
                        update.changes + "";
              arangoHelper.arangoNotification(msg, 15000);

            }
          },
          error: function () {
            // re-schedule the version check
            window.setTimeout(versionCheck, 60000);
          }
        });
      };

      window.setTimeout(versionCheck, 5000);
    },
*/

    logsAllowed: function () {
      return (window.databaseName === '_system');
    },

    checkUser: function () {
      if (window.userCollection.models.length === 0) {
        this.navigate("login", {trigger: true});
        return false;
      }
      return true;
    },

    login: function () {
      if (!this.loginView) {
        this.loginView = new window.loginView({
          collection: window.userCollection
        });
      }
      this.loginView.render();
      this.naviView.selectMenuItem('');
    },

    collections: function() {
      var naviView = this.naviView;
      window.arangoCollectionsStore.fetch({
        success: function () {
          window.collectionsView.render();
          naviView.selectMenuItem('collections-menu');
        }
      });
    },

    collection: function(colid) {
      if (!this.collectionView) {
        this.collectionView = new window.CollectionView();
      }
      this.collectionView.setColId(colid);
      this.collectionView.render();
      this.naviView.selectMenuItem('collections-menu');
    },
    collectionInfo: function(colid) {
      if (!this.collectionInfoView) {
        this.collectionInfoView = new window.CollectionInfoView();
      }
      this.collectionInfoView.setColId(colid);
      this.collectionInfoView.render();
      this.naviView.selectMenuItem('collections-menu');
    },
    newCollection: function() {
      if (!this.newCollectionView) {
        this.newCollectionView = new window.newCollectionView({});
      }
      this.newCollectionView.render();
      this.naviView.selectMenuItem('collections-menu');
    },

    documents: function(colid, pageid) {
      if (!window.documentsView) {
        window.documentsView.initTable(colid, pageid);
      }
      window.documentsView.collectionID = colid;
      var type = arangoHelper.collectionApiType(colid);
      window.documentsView.colid = colid;
      window.documentsView.pageid = pageid;
      window.documentsView.type = type;
      window.documentsView.render();
      window.arangoDocumentsStore.getDocuments(colid, pageid);
    },

    document: function(colid, docid) {
      if (!window.documentView) {
        window.documentView.initTable();
      }
      window.documentView.colid = colid;
      window.documentView.docid = docid;
      window.documentView.render();
      var type = arangoHelper.collectionApiType(colid);
      window.documentView.type = type;
      window.documentView.typeCheck(type);
    },

    source: function(colid, docid) {
      window.documentSourceView.render();
      window.documentSourceView.colid = colid;
      window.documentSourceView.docid = docid;
      var type = arangoHelper.collectionApiType(colid);
      window.documentSourceView.type = type;
      window.documentSourceView.typeCheck(type);
    },

    shell: function() {
      if (!this.shellView) {
        this.shellView = new window.shellView();
      }
      this.shellView.render();
      this.naviView.selectMenuItem('tools-menu');
    },

    query: function() {
      if (!this.queryView) {
        this.queryView = new window.queryView();
      }
      this.queryView.render();
      this.naviView.selectMenuItem('query-menu');
    },

    api: function() {
      if (!this.apiView) {
        this.apiView = new window.apiView();
      }
      this.apiView.render();
      this.naviView.selectMenuItem('tools-menu');
    },

    databases: function() {
      if (arangoHelper.databaseAllowed() === true) {
        if (!this.databaseView) {
          this.databaseView = new window.databaseView({
            collection: arangoDatabase
          });
        }
        this.databaseView.render();
        this.naviView.selectMenuItem('databases-menu');
      }
      else {
        this.navigate("#", {trigger: true});
        this.naviView.selectMenuItem('dashboard-menu');
        $('#databaseNavi').css('display','none');
        $('#databaseNaviSelect').css('display','none');
      }
    },

    logs: function() {
      if (! this.logsAllowed()) {
        this.navigate('', { trigger: true });
        return;
      }

      window.arangoLogsStore.fetch({
        success: function () {
          window.logsView.render();
          $('#logNav a[href="#all"]').tab('show');
          window.logsView.initLogTables();
          window.logsView.drawTable();
          $('#all-switch').click();
        }
      });
      this.naviView.selectMenuItem('tools-menu');
    },

    dashboard: function() {
      this.naviView.selectMenuItem('dashboard-menu');
      if (this.statisticsDescription === undefined) {
        this.statisticsDescription = new window.StatisticsDescription();
        this.statisticsDescription.fetch({
          async:false
        });
      }
      if (this.statistics === undefined) {
        this.statisticsCollection = new window.StatisticsCollection();
      }
      if (this.dashboardView === undefined) {
        this.dashboardView = new dashboardView({
          collection: this.statisticsCollection,
          description: this.statisticsDescription
        });
         }
        this.dashboardView.render();
    },

    graph: function() {
      var self = this;
      window.arangoCollectionsStore.fetch({
        success: function () {
          self.graphView.render();
          self.naviView.selectMenuItem('graphviewer-menu');
        }
      });
    },

    graphManagement: function() {
      if (!this.graphManagementView) {
        this.graphManagementView = new window.GraphManagementView({collection: this.graphs});
      }
      this.graphManagementView.render();
      this.naviView.selectMenuItem('graphviewer-menu');
    },

    graphAddNew: function() {
      if (!this.addNewGraphView) {
        this.addNewGraphView = new window.AddNewGraphView({
          collection: window.arangoCollectionsStore,
          graphs: this.graphs
        });
      }
      this.addNewGraphView.render();
      this.naviView.selectMenuItem('graphviewer-menu');
    },

    graphDelete: function(name) {
      if (!this.deleteGraphView) {
        this.deleteGraphView = new window.DeleteGraphView({
          collection: this.graphs
        });
      }
      this.deleteGraphView.render(name);
      this.naviView.selectMenuItem('graphviewer-menu');
    },

    applications: function() {
      if (this.applicationsView === undefined) {
        this.applicationsView = new window.ApplicationsView({
          collection: this.foxxList
        });
      }
      this.applicationsView.reload();
      this.naviView.selectMenuItem('applications-menu');
    },

    applicationsAvailable: function() {
      if (this.applicationsInstalledView === undefined) {
        this.applicationsInstalledView = new window.FoxxInstalledListView({
          collection: this.foxxList
        });
      }
      this.applicationsInstalledView.reload();
      this.naviView.selectMenuItem('applications-menu');
    },

    applicationsInstalled: function() {
      if (this.applicationsActiveView === undefined) {
        this.applicationsActiveView = new window.FoxxActiveListView({
          collection: this.foxxList
        });
      }
      this.applicationsActiveView.reload();
      this.naviView.selectMenuItem('applications-menu');
    },

    applicationEdit: function(appkey) {
      this.foxxList.fetch({
        async: false
      });
      var editAppView = new window.foxxEditView({model: this.foxxList.findWhere({_key: appkey})});
      editAppView.render();
    },

    applicationInstall: function(appkey) {
      this.foxxList.fetch({
        async: false
      });
      if (!this.installAppView) {
        this.installAppView = new window.foxxMountView({
          collection: this.foxxList
        });
      }
      this.installAppView.render(appkey);
    },

    appDocumentation: function(key) {
      var docuView = new window.AppDocumentationView({key: key});
      docuView.render();
      this.naviView.selectMenuItem('applications-menu');
    },

    handleSelectDatabase: function () {
      this.naviView.handleSelectDatabase();
    },

    handleResize: function () {
      var oldWidth = $('#content').width();
      var containerWidth = $(window).width() - 70;
      /*var spanWidth = 242;*/
      var spanWidth = 243;
      var divider = containerWidth / spanWidth;
      var roundDiv = parseInt(divider, 10);
      var newWidth = roundDiv*spanWidth -2;
      var marginWidth = ((containerWidth+30) - newWidth)/2;
      /*
      $('#content').width(newWidth)
      .css('margin-left', marginWidth)
      .css('margin-right', marginWidth);
      */
      // $('.footer-right p').css('margin-right', marginWidth + 20);
      // $('.footer-left p').css('margin-left', marginWidth + 20);
      if (newWidth !== oldWidth) {
        this.graphView.handleResize(newWidth);
      }
    },

    userManagement: function() {
      if (!this.userManagementView) {
        this.userManagementView = new window.userManagementView({
          collection: window.userCollection
        });
      }
      this.userManagementView.render();
      this.naviView.selectMenuItem('user-menu');
    },

    userProfile: function() {
      if (!this.userProfileView) {
        this.userProfileView = new window.userProfileView({
          collection: window.userCollection
        });
      }
      this.userProfileView.render();
      this.naviView.selectMenuItem('user-menu');
    }

  });

}());
<|endoftext|>


<commit_before>import React from 'react';
import blacklist from 'blacklist';

var FooterBar = React.createClass({
	propTypes: {
		style: React.PropTypes.object,
	},
	getDefaultProps () {
		return {
			style: {},
		};
	},
	getInitialState () {
		return {
			position: 'relative',
			width: 'auto',
			height: 'auto',
			top: 0,
		};
	},
	componentDidMount () {
		// Bail in IE8 because React doesn't support the onScroll event in that browser
		// Conveniently (!) IE8 doesn't have window.getComputedStyle which we also use here
		if (!window.getComputedStyle) return;
		var footer = this.refs.footer;
		this.windowSize = this.getWindowSize();
		var footerStyle = window.getComputedStyle(footer);
		this.footerSize = {
			x: footer.offsetWidth,
			y: footer.offsetHeight + parseInt(footerStyle.marginTop || '0'),
		};
		window.addEventListener('scroll', this.recalcPosition, false);
		window.addEventListener('resize', this.recalcPosition, false);
		this.recalcPosition();
	},
	getWindowSize () {
		return {
			x: window.innerWidth,
			y: window.innerHeight,
		};
	},
	recalcPosition () {
		var wrapper = this.refs.wrapper;

		this.footerSize.x = wrapper.offsetWidth;

		var offsetTop = 0;
		var offsetEl = wrapper;

		while (offsetEl) {
			offsetTop += offsetEl.offsetTop;
			offsetEl = offsetEl.offsetParent;
		}

		var maxY = offsetTop + this.footerSize.y;
		var viewY = window.scrollY + window.innerHeight;

		var newSize = this.getWindowSize();
		var sizeChanged = (newSize.x !== this.windowSize.x || newSize.y !== this.windowSize.y);
		this.windowSize = newSize;

		var newState = {
			width: this.footerSize.x,
			height: this.footerSize.y,
		};

		if (viewY > maxY && (sizeChanged || this.mode !== 'inline')) {
			this.mode = 'inline';
			newState.top = 0;
			newState.position = 'absolute';
			this.setState(newState);
		} else if (viewY <= maxY && (sizeChanged || this.mode !== 'fixed')) {
			this.mode = 'fixed';
			newState.top = window.innerHeight - this.footerSize.y;
			newState.position = 'fixed';
			this.setState(newState);
		}
	},
	render () {
		var wrapperStyle = {
			height: this.state.height,
			marginTop: 60,
			position: 'relative',
		};
		var footerProps = blacklist(this.props, 'children', 'style');
		var footerStyle = Object.assign({}, this.props.style, {
			position: this.state.position,
			top: this.state.top,
			width: this.state.width,
			height: this.state.height,
		});
		return (

{this.props.children}

		);
	},
});

module.exports = FooterBar;
<commit_msg>FooterBar component needs to unbind event listeners before Unmount<commit_after>import React from 'react';
import blacklist from 'blacklist';

var FooterBar = React.createClass({
	propTypes: {
		style: React.PropTypes.object,
	},
	getDefaultProps () {
		return {
			style: {},
		};
	},
	getInitialState () {
		return {
			position: 'relative',
			width: 'auto',
			height: 'auto',
			top: 0,
		};
	},
	componentDidMount () {
		// Bail in IE8 because React doesn't support the onScroll event in that browser
		// Conveniently (!) IE8 doesn't have window.getComputedStyle which we also use here
		if (!window.getComputedStyle) return;
		var footer = this.refs.footer;
		this.windowSize = this.getWindowSize();
		var footerStyle = window.getComputedStyle(footer);
		this.footerSize = {
			x: footer.offsetWidth,
			y: footer.offsetHeight + parseInt(footerStyle.marginTop || '0'),
		};
		window.addEventListener('scroll', this.recalcPosition, false);
		window.addEventListener('resize', this.recalcPosition, false);
		this.recalcPosition();
	},
	componentWillUnmount () {
		window.removeEventListener('scroll', this.recalcPosition, false);
		window.removeEventListener('resize', this.recalcPosition, false);
	},
	getWindowSize () {
		return {
			x: window.innerWidth,
			y: window.innerHeight,
		};
	},
	recalcPosition () {
		var wrapper = this.refs.wrapper;

		this.footerSize.x = wrapper.offsetWidth;

		var offsetTop = 0;
		var offsetEl = wrapper;

		while (offsetEl) {
			offsetTop += offsetEl.offsetTop;
			offsetEl = offsetEl.offsetParent;
		}

		var maxY = offsetTop + this.footerSize.y;
		var viewY = window.scrollY + window.innerHeight;

		var newSize = this.getWindowSize();
		var sizeChanged = (newSize.x !== this.windowSize.x || newSize.y !== this.windowSize.y);
		this.windowSize = newSize;

		var newState = {
			width: this.footerSize.x,
			height: this.footerSize.y,
		};

		if (viewY > maxY && (sizeChanged || this.mode !== 'inline')) {
			this.mode = 'inline';
			newState.top = 0;
			newState.position = 'absolute';
			this.setState(newState);
		} else if (viewY <= maxY && (sizeChanged || this.mode !== 'fixed')) {
			this.mode = 'fixed';
			newState.top = window.innerHeight - this.footerSize.y;
			newState.position = 'fixed';
			this.setState(newState);
		}
	},
	render () {
		var wrapperStyle = {
			height: this.state.height,
			marginTop: 60,
			position: 'relative',
		};
		var footerProps = blacklist(this.props, 'children', 'style');
		var footerStyle = Object.assign({}, this.props.style, {
			position: this.state.position,
			top: this.state.top,
			width: this.state.width,
			height: this.state.height,
		});
		return (

{this.props.children}

		);
	},
});

module.exports = FooterBar;
<|endoftext|>


<commit_before>import { bindable, customAttribute } from 'aurelia-templating';
import { bindingMode } from 'aurelia-binding';
import { inject } from 'aurelia-dependency-injection';
import { AttributeManager } from '../common/attributeManager';
import { getBooleanFromAttributeValue } from '../common/attributes';

@customAttribute('md-dropdown')
@inject(Element)
export class MdDropdown {
  static elementId = 0;

  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) activates = '';
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) ref = null;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) alignment = 'left';
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) belowOrigin = false;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) constrainWidth = true;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) gutter = 0;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) hover = false;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) mdTitle;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) inDuration = 300;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) outDuration = 225;

  constructor(element) {
    this.element = element;
    this.attributeManager = new AttributeManager(this.element);
  }

  attached() {
    this.handleActivateElement();
    this.contentAttributeManager = new AttributeManager(document.getElementById(this.activates));

    this.attributeManager.addClasses('dropdown-button');
    this.contentAttributeManager.addClasses('dropdown-content');
    // this.attributeManager.addAttributes({ 'data-activates': this.activates });

    $(this.element).dropdown({
      alignment: this.alignment,
      belowOrigin: getBooleanFromAttributeValue(this.belowOrigin),
      constrain_width: getBooleanFromAttributeValue(this.constrainWidth),
      gutter: parseInt(this.gutter, 10),
      hover: getBooleanFromAttributeValue(this.hover),
      inDuration: parseInt(this.inDuration, 10),
      outDuration: parseInt(this.outDuration, 10)
    });
  }

  detached() {
    this.attributeManager.removeAttributes('data-activates');
    this.attributeManager.removeClasses('dropdown-button');
    this.contentAttributeManager.removeClasses('dropdown-content');
  }

  handleActivateElement() {
    if (this.ref) {
      let id = this.ref.getAttribute('id');
      if (!id) {
        id = `md-dropdown-${MdDropdown.elementId++}`;
        this.ref.setAttribute('id', id);
        this.activates = id;
      }
      this.id = MdDropdown.elementId++;
    }
    this.attributeManager.addAttributes({ 'data-activates': this.activates });
  }
}
<commit_msg>feat(md-dropdown): add support for camelCase options<commit_after>import { bindable, customAttribute } from 'aurelia-templating';
import { bindingMode } from 'aurelia-binding';
import { inject } from 'aurelia-dependency-injection';
import { AttributeManager } from '../common/attributeManager';
import { getBooleanFromAttributeValue } from '../common/attributes';

@customAttribute('md-dropdown')
@inject(Element)
export class MdDropdown {
  static elementId = 0;

  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) activates = '';
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) ref = null;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) alignment = 'left';
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) belowOrigin = false;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) constrainWidth = true;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) gutter = 0;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) hover = false;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) mdTitle;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) inDuration = 300;
  @bindable({
    defaultBindingMode: bindingMode.oneTime
  }) outDuration = 225;

  constructor(element) {
    this.element = element;
    this.attributeManager = new AttributeManager(this.element);
  }

  attached() {
    this.handleActivateElement();
    this.contentAttributeManager = new AttributeManager(document.getElementById(this.activates));

    this.attributeManager.addClasses('dropdown-button');
    this.contentAttributeManager.addClasses('dropdown-content');
    // this.attributeManager.addAttributes({ 'data-activates': this.activates });

    $(this.element).dropdown({
      alignment: this.alignment,
      belowOrigin: getBooleanFromAttributeValue(this.belowOrigin),
      constrain_width: getBooleanFromAttributeValue(this.constrainWidth),
      constrainWidth: getBooleanFromAttributeValue(this.constrainWidth),
      gutter: parseInt(this.gutter, 10),
      hover: getBooleanFromAttributeValue(this.hover),
      inDuration: parseInt(this.inDuration, 10),
      outDuration: parseInt(this.outDuration, 10)
    });
  }

  detached() {
    this.attributeManager.removeAttributes('data-activates');
    this.attributeManager.removeClasses('dropdown-button');
    this.contentAttributeManager.removeClasses('dropdown-content');
  }

  handleActivateElement() {
    if (this.ref) {
      let id = this.ref.getAttribute('id');
      if (!id) {
        id = `md-dropdown-${MdDropdown.elementId++}`;
        this.ref.setAttribute('id', id);
        this.activates = id;
      }
      this.id = MdDropdown.elementId++;
    }
    this.attributeManager.addAttributes({ 'data-activates': this.activates });
  }
}
<|endoftext|>


<commit_before>/* eslint-disable react/forbid-prop-types */
/* eslint-disable import/prefer-default-export */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import React, { useCallback, useState, useEffect } from 'react';
import PropTypes from 'prop-types';

import { StyleSheet, TextInput, View, TouchableOpacity } from 'react-native';
import { MagnifyingGlass, Cancel } from './icons';
import { SUSSOL_ORANGE } from '../globalStyles/index';
import { debounce } from '../utilities/index';

/**
 * Simple search bar - essentially a wrapper around a text input
 * with a magnifying glass icon and clear button.
 *
 * Debounces input by the user, such that the onChangeText callback
 * is only invoked once every `debounceTimeout`.
 *
 * NOTE: This component is exported MEMOIZED. See below for propsAreEqual
 * implementation.
 *
 * @param {String} color           Color of the entire component (monochrome only).
 * @param {String} onChangeText    Callback for changing text (debounced).
 * @param {String} value           Text value of the search input.
 * @param {String} placeholder     Placeholder value.
 * @param {String} autoFocus       Autofocus this component on mounting.
 * @param {String} textInputStyle  Style of the TextInput component.
 * @param {String} viewStyle       Style of the wrapping View component.
 * @param {String} debounceTimeout Time in milliseconds to debounce the onChangeText callback.
 * @param {Func}   onFocusOrBlur   Callback for onBlur and onFocus events.
 */
export const SearchBarComponent = ({
  color,
  onChangeText,
  value,
  placeholder,
  autoFocus,
  textInputStyle,
  viewStyle,
  debounceTimeout,
  onFocusOrBlur,
  ...textInputProps
}) => {
  const [textValue, setTextValue] = useState('');

  // Set the internal text value if it differs from the passed
  // value. Keeping the search bar text input up to date with
  // user input while debouncing actual filtering of data.
  useEffect(() => {
    if (value !== textValue) setTextValue(value);
  }, [value]);

  const internalViewStyle = { ...viewStyle, borderColor: color };
  const internalTextStyle = { ...textInputStyle, color };

  // To debounce a function, need to use the same function as the
  // last call. Memoize this to keep the reference semi-stable. Keeping
  // this reference is an optimization, not a requirement so can change.
  const debouncedCallback = useCallback(
    debounce(newValue => onChangeText(newValue), debounceTimeout),
    []
  );

  // On text change, set the internal text value, and call the debounced
  // callback. Keep the users input upto date, but optimize filtering.
  const onChangeTextCallback = useCallback(newValue => {
    setTextValue(newValue);
    debouncedCallback(newValue);
  }, []);

  return (
    <View style={internalViewStyle}>
      <MagnifyingGlass />
      <TextInput
        {...textInputProps}
        style={internalTextStyle}
        value={textValue}
        underlineColorAndroid="transparent"
        placeholderTextColor={color}
        placeholder={placeholder}
        onChangeText={onChangeTextCallback}
        autoFocus={autoFocus}
        onFocus={onFocusOrBlur}
        onBlur={onFocusOrBlur}
        selectTextOnFocus
      />
      {!!textValue && (
        <TouchableOpacity onPress={() => onChangeTextCallback('')}>
          <Cancel />
        </TouchableOpacity>
      )}
    </View>
  );
};

/**
 * Only re-render this component when the value or onFocusOrBlur
 * props change.
 */
const propsAreEqual = (
  { value: prevValue, onFocusOrBlur: prevOnFocusOrBlur },
  { value: nextValue, onFocusOrBlur: nextOnFocusOrBlur }
) => {
  const valuesAreEqual = prevValue === nextValue;
  const onFocusOrBlueAreEqual = prevOnFocusOrBlur === nextOnFocusOrBlur;
  return valuesAreEqual && onFocusOrBlueAreEqual;
};

export const SearchBar = React.memo(SearchBarComponent, propsAreEqual);

const defaultStyles = StyleSheet.create({
  container: {
    borderBottomWidth: 1,
    flexDirection: 'row',
    alignItems: 'center',
    marginHorizontal: 5,
  },
  textInput: {
    height: 40,
    fontSize: 16,
    backgroundColor: 'rgba(0, 0, 0, 0)',
    flex: 1,
  },
});

SearchBarComponent.defaultProps = {
  debounceTimeout: 250,
  textInputStyle: defaultStyles.textInput,
  viewStyle: defaultStyles.container,
  color: SUSSOL_ORANGE,
  value: '',
  placeholder: '',
  autoFocus: false,
  onFocusOrBlur: null,
};

SearchBarComponent.propTypes = {
  color: PropTypes.string,
  debounceTimeout: PropTypes.number,
  onChangeText: PropTypes.func.isRequired,
  value: PropTypes.string,
  placeholder: PropTypes.string,
  autoFocus: PropTypes.bool,
  textInputStyle: PropTypes.object,
  viewStyle: PropTypes.object,
  onFocusOrBlur: PropTypes.func,
};
<commit_msg>Add corrected spelling<commit_after>/* eslint-disable react/forbid-prop-types */
/* eslint-disable import/prefer-default-export */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import React, { useCallback, useState, useEffect } from 'react';
import PropTypes from 'prop-types';

import { StyleSheet, TextInput, View, TouchableOpacity } from 'react-native';
import { MagnifyingGlass, Cancel } from './icons';
import { SUSSOL_ORANGE } from '../globalStyles/index';
import { debounce } from '../utilities/index';

/**
 * Simple search bar - essentially a wrapper around a text input
 * with a magnifying glass icon and clear button.
 *
 * Debounces input by the user, such that the onChangeText callback
 * is only invoked once every `debounceTimeout`.
 *
 * NOTE: This component is exported MEMOIZED. See below for propsAreEqual
 * implementation.
 *
 * @param {String} color           Color of the entire component (monochrome only).
 * @param {String} onChangeText    Callback for changing text (debounced).
 * @param {String} value           Text value of the search input.
 * @param {String} placeholder     Placeholder value.
 * @param {String} autoFocus       Autofocus this component on mounting.
 * @param {String} textInputStyle  Style of the TextInput component.
 * @param {String} viewStyle       Style of the wrapping View component.
 * @param {String} debounceTimeout Time in milliseconds to debounce the onChangeText callback.
 * @param {Func}   onFocusOrBlur   Callback for onBlur and onFocus events.
 */
export const SearchBarComponent = ({
  color,
  onChangeText,
  value,
  placeholder,
  autoFocus,
  textInputStyle,
  viewStyle,
  debounceTimeout,
  onFocusOrBlur,
  ...textInputProps
}) => {
  const [textValue, setTextValue] = useState('');

  // Set the internal text value if it differs from the passed
  // value. Keeping the search bar text input up to date with
  // user input while debouncing actual filtering of data.
  useEffect(() => {
    if (value !== textValue) setTextValue(value);
  }, [value]);

  const internalViewStyle = { ...viewStyle, borderColor: color };
  const internalTextStyle = { ...textInputStyle, color };

  // To debounce a function, need to use the same function as the
  // last call. Memoize this to keep the reference semi-stable. Keeping
  // this reference is an optimization, not a requirement so can change.
  const debouncedCallback = useCallback(
    debounce(newValue => onChangeText(newValue), debounceTimeout),
    []
  );

  // On text change, set the internal text value, and call the debounced
  // callback. Keep the users input upto date, but optimize filtering.
  const onChangeTextCallback = useCallback(newValue => {
    setTextValue(newValue);
    debouncedCallback(newValue);
  }, []);

  return (
    <View style={internalViewStyle}>
      <MagnifyingGlass />
      <TextInput
        {...textInputProps}
        style={internalTextStyle}
        value={textValue}
        underlineColorAndroid="transparent"
        placeholderTextColor={color}
        placeholder={placeholder}
        onChangeText={onChangeTextCallback}
        autoFocus={autoFocus}
        onFocus={onFocusOrBlur}
        onBlur={onFocusOrBlur}
        selectTextOnFocus
      />
      {!!textValue && (
        <TouchableOpacity onPress={() => onChangeTextCallback('')}>
          <Cancel />
        </TouchableOpacity>
      )}
    </View>
  );
};

/**
 * Only re-render this component when the value or onFocusOrBlur
 * props change.
 */
const propsAreEqual = (
  { value: prevValue, onFocusOrBlur: prevOnFocusOrBlur },
  { value: nextValue, onFocusOrBlur: nextOnFocusOrBlur }
) => {
  const valuesAreEqual = prevValue === nextValue;
  const onFocusOrBlurAreEqual = prevOnFocusOrBlur === nextOnFocusOrBlur;
  return valuesAreEqual && onFocusOrBlurAreEqual;
};

export const SearchBar = React.memo(SearchBarComponent, propsAreEqual);

const defaultStyles = StyleSheet.create({
  container: {
    borderBottomWidth: 1,
    flexDirection: 'row',
    alignItems: 'center',
    marginHorizontal: 5,
  },
  textInput: {
    height: 40,
    fontSize: 16,
    backgroundColor: 'rgba(0, 0, 0, 0)',
    flex: 1,
  },
});

SearchBarComponent.defaultProps = {
  debounceTimeout: 250,
  textInputStyle: defaultStyles.textInput,
  viewStyle: defaultStyles.container,
  color: SUSSOL_ORANGE,
  value: '',
  placeholder: '',
  autoFocus: false,
  onFocusOrBlur: null,
};

SearchBarComponent.propTypes = {
  color: PropTypes.string,
  debounceTimeout: PropTypes.number,
  onChangeText: PropTypes.func.isRequired,
  value: PropTypes.string,
  placeholder: PropTypes.string,
  autoFocus: PropTypes.bool,
  textInputStyle: PropTypes.object,
  viewStyle: PropTypes.object,
  onFocusOrBlur: PropTypes.func,
};
<|endoftext|>


<commit_before>import React from 'react';
import PropForm from './PropForm';
import tosource from 'tosource';

const styles = {
  panel: {
    padding: '5px',
    backgroundColor: 'rgb(247, 247, 247)',
    width: '100%',
  },
  noKnobs: {
    fontFamily: `
      -apple-system, ".SFNSText-Regular", "San Francisco", "Roboto",
      "Segoe UI", "Helvetica Neue", "Lucida Grande", sans-serif
    `,
    display: 'inline',
    backgroundColor: 'rgb(247, 247, 247)',
    width: '100%',
    textAlign: 'center',
    color: 'rgb(190, 190, 190)',
    padding: '10px',
  },
  resetButton: {
    color: 'rgb(130, 130, 130)',
    float: 'right',
    marginRight: '5px',
    marginTop: '5px',
  },
};

export default class Panel extends React.Component {
  constructor(props) {
    super(props);
    this._handleChange = this.handleChange.bind(this);
    this._setFields = this.setFields.bind(this);
    this._reset = this.reset.bind(this);
    this._setInitialFields = this.setInitialFields.bind(this);
    this._indicateReady = this.indicateReady.bind(this);

    this.state = { fields: {} };
    this.api = this.props.api;
  }

  componentWillMount() {
    const urlState = this.api.getQueryParam('knobs');

    if (urlState && urlState.length > 0) {
      this.initialFields = JSON.parse(urlState);
    }

    if (this.initialFields) {
      this.props.channel.on('addon:knobs:helloFromStory', this._setInitialFields);
      this.setState({ fields: this.initialFields });
    } else {
      this.props.channel.on('addon:knobs:helloFromStory', this._indicateReady);
    }
  }

  componentDidMount() {
    this.stopOnStory = this.api.onStory(() => {
      this.setState({ fields: {} });
    });

    this.props.channel.on('addon:knobs:setFields', this._setFields);
    this.props.channel.emit('addon:knobs:helloFromPanel');
  }

  componentWillUnmount() {
    this.props.channel.removeListener('addon:knobs:setFields', this._setFields);
    this.props.channel.removeListener('addon:knobs:helloFromStory', this._indicateReady);
    this.props.channel.removeListener('addon:knobs:helloFromStory', this._setInitialFields);
    this.api.setQueryParams({ knobs: null });
    this.stopOnStory();
  }

  setInitialFields() {
    this.props.channel.emit('addon:knobs:initialFields', this.initialFields);
    this.props.channel.removeListener('addon:knobs:helloFromStory', this._setInitialFields);
    this.props.channel.on('addon:knobs:helloFromStory', this._indicateReady);
  }

  setFields(_fields) {
    const fields = _fields;
    for (const f in fields) {
      if (fields.hasOwnProperty(f)) {
        if (fields[f].type === 'object') {
          fields[f].value = tosource(fields[f].value);
        }
      }
    }
    this.setState({ fields });
    this.api.setQueryParams({ knobs: JSON.stringify(fields) });
  }

  indicateReady() {
    this.props.channel.emit('addon:knobs:panelReady');
  }

  reset() {
    this.props.channel.emit('addon:knobs:reset');
  }

  handleChange(change) {
    const { name, value } = change;

    const fields = this.state.fields;
    const changedField = {};
    changedField[name] = { ...fields[name], ...{ value } };
    const newFields = { ...fields, ...changedField };
    this.setState({ fields: newFields });
    this.api.setQueryParams({ knobs: JSON.stringify(newFields) });

    this.props.channel.emit('addon:knobs:knobChange', change);
  }

  render() {
    if (!this.state.fields) {
      return (

NO KNOBS

      );
    }

    return (

        <PropForm fields={this.state.fields} onFieldChange={this._handleChange} />
        <button style={styles.resetButton} onClick={this._reset}>RESET</button>

    );
  }
}

Panel.propTypes = {
  channel: React.PropTypes.object,
  onReset: React.PropTypes.object,
  api: React.PropTypes.object,
};
<commit_msg>Set fields to null onStory so when a story is not wrapped "no knobs" is displayed<commit_after>import React from 'react';
import PropForm from './PropForm';
import tosource from 'tosource';

const styles = {
  panel: {
    padding: '5px',
    backgroundColor: 'rgb(247, 247, 247)',
    width: '100%',
  },
  noKnobs: {
    fontFamily: `
      -apple-system, ".SFNSText-Regular", "San Francisco", "Roboto",
      "Segoe UI", "Helvetica Neue", "Lucida Grande", sans-serif
    `,
    display: 'inline',
    backgroundColor: 'rgb(247, 247, 247)',
    width: '100%',
    textAlign: 'center',
    color: 'rgb(190, 190, 190)',
    padding: '10px',
  },
  resetButton: {
    color: 'rgb(130, 130, 130)',
    float: 'right',
    marginRight: '5px',
    marginTop: '5px',
  },
};

export default class Panel extends React.Component {
  constructor(props) {
    super(props);
    this._handleChange = this.handleChange.bind(this);
    this._setFields = this.setFields.bind(this);
    this._reset = this.reset.bind(this);
    this._setInitialFields = this.setInitialFields.bind(this);
    this._indicateReady = this.indicateReady.bind(this);

    this.state = { fields: null };
    this.api = this.props.api;
  }

  componentWillMount() {
    const urlState = this.api.getQueryParam('knobs');

    if (urlState && urlState.length > 0) {
      this.initialFields = JSON.parse(urlState);
    }

    if (this.initialFields) {
      this.props.channel.on('addon:knobs:helloFromStory', this._setInitialFields);
      this.setState({ fields: this.initialFields });
    } else {
      this.props.channel.on('addon:knobs:helloFromStory', this._indicateReady);
    }
  }

  componentDidMount() {
    this.stopOnStory = this.api.onStory(() => {
      this.setState({ fields: null });
      this.api.setQueryParams({ knobs: null });
    });

    this.props.channel.on('addon:knobs:setFields', this._setFields);
    this.props.channel.emit('addon:knobs:helloFromPanel');
  }

  componentWillUnmount() {
    this.props.channel.removeListener('addon:knobs:setFields', this._setFields);
    this.props.channel.removeListener('addon:knobs:helloFromStory', this._indicateReady);
    this.props.channel.removeListener('addon:knobs:helloFromStory', this._setInitialFields);
    this.stopOnStory();
  }

  setInitialFields() {
    this.props.channel.emit('addon:knobs:initialFields', this.initialFields);
    this.props.channel.removeListener('addon:knobs:helloFromStory', this._setInitialFields);
    this.props.channel.on('addon:knobs:helloFromStory', this._indicateReady);
  }

  setFields(_fields) {
    const fields = _fields;
    for (const f in fields) {
      if (fields.hasOwnProperty(f)) {
        if (fields[f].type === 'object') {
          fields[f].value = tosource(fields[f].value);
        }
      }
    }
    this.setState({ fields });
    this.api.setQueryParams({ knobs: JSON.stringify(fields) });
  }

  indicateReady() {
    this.props.channel.emit('addon:knobs:panelReady');
  }

  reset() {
    this.props.channel.emit('addon:knobs:reset');
  }

  handleChange(change) {
    const { name, value } = change;

    const fields = this.state.fields;
    const changedField = {};
    changedField[name] = { ...fields[name], ...{ value } };
    const newFields = { ...fields, ...changedField };
    this.setState({ fields: newFields });
    this.api.setQueryParams({ knobs: JSON.stringify(newFields) });

    this.props.channel.emit('addon:knobs:knobChange', change);
  }

  render() {
    if (!this.state.fields) {
      return (

NO KNOBS

      );
    }

    return (

        <PropForm fields={this.state.fields} onFieldChange={this._handleChange} />
        <button style={styles.resetButton} onClick={this._reset}>RESET</button>

    );
  }
}

Panel.propTypes = {
  channel: React.PropTypes.object,
  onReset: React.PropTypes.object,
  api: React.PropTypes.object,
};
<|endoftext|>


<commit_before>// IE<9 lacks Array.prototype.indexOf
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(needle) {
        for (i=0, l=this.length; i<l; ++i) {
            if (this[i] === needle) return i;
        }
        return -1;
    }
}

django.jQuery(function($){
    // Patch up urlify maps to generate nicer slugs in german
    if(typeof(Downcoder) != "undefined"){
        Downcoder.Initialize() ;
        Downcoder.map["ö"] = Downcoder.map["Ö"] = "oe";
        Downcoder.map["ä"] = Downcoder.map["Ä"] = "ae";
        Downcoder.map["ü"] = Downcoder.map["Ü"] = "ue";
    }

    /* .dataset.context instead of getAttribute would be nicer */
    var ItemEditor = JSON.parse(
        document.getElementById('item-editor-script').getAttribute('data-context'));

    $('h2:contains(' + ItemEditor.feincmsContentFieldsetName + ')').parent().replaceWith($('#main_wrapper'));

    var inlineGroups = (function() {
        var selector = [];
        $.each(ItemEditor.plugins, function(key, value) {
            selector.push('#' + key + '_set-group');
        });
        return $(selector.join(', '));
    })();

    var inlines = inlineGroups.find('.inline-related').detach();
    inlines.sort(function inlinesCompareFunction(a, b) {
        var aOrdering = $(a).find('.field-ordering input').val() || 1e9;
        var bOrdering = $(b).find('.field-ordering input').val() || 1e9;
        return Math.sign(aOrdering - bOrdering);
    });
    $('.order-machine').append(inlines);

    $('.order-machine .inline-related').not('.empty-form').each(function assignRegionDataAttribute() {
        var $this = $(this),
            region = $this.find('.field-region input').val();

        // Have to use attr() here because we want the data attribute to
        // be visible to selectors.
        $this.attr('data-region', region);
    });

    function moveEmptyFormsToEnd() {
        $('.order-machine').append(
            $('.order-machine .empty-form').detach()
        );
    }
    moveEmptyFormsToEnd();

    $(document).on('formset:added', function newForm(event, row, optionsPrefix) {
        moveEmptyFormsToEnd();

        var currentRegion = $('.tabs>.active').data('region');
        row.find('.field-region input').val(currentRegion);
        row.attr('data-region', currentRegion);
    });

    function selectRegion(name) {
        $('.tabs>div').removeClass('active').filter('[data-region="' + name + '"]').addClass('active');
        $('.order-machine .inline-related').not('.empty-form').hide().filter('[data-region="' + name + '"]').show();
    }

    $(document).on('click', '.tabs>div', function() {
        selectRegion($(this).data('region'));
    });

    $('.tabs>div:first').trigger('click');

    $('.order-machine').sortable({
        handle: 'h3',
        placeholder: 'placeholder'
    });
    $('.order-machine').on('click', '.delete>input[type=checkbox]', function() {
        $(this).closest('.inline-related')[this.checked ? 'addClass' : 'removeClass']('for-deletion');
    });

    $('form').submit(function(){
        $('.field-ordering input').each(function assignOrdering(index) {
            this.value = index;
        });

        var form = $(this);
        form.attr('action', form.attr('action') + window.location.hash);
        return true;
    });

    $(document).keydown(function handleCmdS(event) {
        if(event.which == 83 && event.metaKey) {
            $('form input[name=' + (event.shiftKey ? '_continue' : '_save') + ']').click();
            return false;
        }
    });

})
<commit_msg>Allow cancelling sorts<commit_after>// IE<9 lacks Array.prototype.indexOf
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(needle) {
        for (i=0, l=this.length; i<l; ++i) {
            if (this[i] === needle) return i;
        }
        return -1;
    }
}

django.jQuery(function($){
    // Patch up urlify maps to generate nicer slugs in german
    if(typeof(Downcoder) != "undefined"){
        Downcoder.Initialize() ;
        Downcoder.map["ö"] = Downcoder.map["Ö"] = "oe";
        Downcoder.map["ä"] = Downcoder.map["Ä"] = "ae";
        Downcoder.map["ü"] = Downcoder.map["Ü"] = "ue";
    }

    /* .dataset.context instead of getAttribute would be nicer */
    var ItemEditor = JSON.parse(
        document.getElementById('item-editor-script').getAttribute('data-context'));

    $('h2:contains(' + ItemEditor.feincmsContentFieldsetName + ')').parent().replaceWith($('#main_wrapper'));

    var inlineGroups = (function() {
        var selector = [];
        $.each(ItemEditor.plugins, function(key, value) {
            selector.push('#' + key + '_set-group');
        });
        return $(selector.join(', '));
    })();

    var inlines = inlineGroups.find('.inline-related').detach();
    inlines.sort(function inlinesCompareFunction(a, b) {
        var aOrdering = $(a).find('.field-ordering input').val() || 1e9;
        var bOrdering = $(b).find('.field-ordering input').val() || 1e9;
        return Math.sign(aOrdering - bOrdering);
    });
    $('.order-machine').append(inlines);

    $('.order-machine .inline-related').not('.empty-form').each(function assignRegionDataAttribute() {
        var $this = $(this),
            region = $this.find('.field-region input').val();

        // Have to use attr() here because we want the data attribute to
        // be visible to selectors.
        $this.attr('data-region', region);
    });

    function moveEmptyFormsToEnd() {
        $('.order-machine').append(
            $('.order-machine .empty-form').detach()
        );
    }
    moveEmptyFormsToEnd();

    $(document).on('formset:added', function newForm(event, row, optionsPrefix) {
        moveEmptyFormsToEnd();

        var currentRegion = $('.tabs>.active').data('region');
        row.find('.field-region input').val(currentRegion);
        row.attr('data-region', currentRegion);
    });

    function selectRegion(name) {
        $('.tabs>div').removeClass('active').filter('[data-region="' + name + '"]').addClass('active');
        $('.order-machine .inline-related').not('.empty-form').hide().filter('[data-region="' + name + '"]').show();
    }

    $(document).on('click', '.tabs>div', function() {
        selectRegion($(this).data('region'));
    });

    $('.tabs>div:first').trigger('click');

    $('.order-machine').sortable({
        handle: 'h3',
        placeholder: 'placeholder'
    });
    $('.order-machine').on('click', '.delete>input[type=checkbox]', function() {
        $(this).closest('.inline-related')[this.checked ? 'addClass' : 'removeClass']('for-deletion');
    });

    $('form').submit(function(){
        $('.field-ordering input').each(function assignOrdering(index) {
            this.value = index;
        });

        var form = $(this);
        form.attr('action', form.attr('action') + window.location.hash);
        return true;
    });

    $(document).keydown(function handleKeys(event) {
        if (event.which == 83 && event.metaKey) {
            $('form input[name=' + (event.shiftKey ? '_continue' : '_save') + ']').click();
            return false;
        } else if (event.which == 27) {
            $('.order-machine').sortable('cancel');
        }
    });

})
<|endoftext|>


<commit_before>//    Copyright 2017 drillbits
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

const hijack = {};

hijack.getCookie = (nightmare, email, password, fileID, waitMsec) => {
    if (!waitMsec || isNaN(waitMsec)) {
        waitMsec = 3000;
    }
    return nightmare
        .goto('https://accounts.google.com/ServiceLogin')
        .wait('#identifierId')
        .type('#identifierId', email)
        .click('#identifierNext')
        .wait("input[type=password]")
        .wait(2000) // WORKAROUND
        .type("input[type=password]", password)
        .click('#passwordNext')
        .wait(waitMsec)
        .goto(`https://drive.google.com/file/d/${fileID}/view`)
        .cookies.get('DRIVE_STREAM');
};

hijack.extractStreamMap = (nightmare, fileID, cookie) => {
    return nightmare
        .cookies.set(cookie)
        .goto(`https://drive.google.com/file/d/${fileID}/view`)
        .evaluate(() => {
            const html = document.body.innerHTML,
                s = html.indexOf('_initProjector'),
                e = html.indexOf('</script>', s),
                init = html.slice(s, e),
                streamMap = {};

            const _initProjector = (a, b, c) => {
                return c[19][0][17][1];
            }
            const fmtStreamMap = eval(init);
            fmtStreamMap.split(',').map((x) => {
                const spl = x.split('|');
                const iTag = parseInt(spl[0], 10);
                streamMap[iTag] = spl[1];
            });
            return streamMap;
        });
};

module.exports = hijack;
<commit_msg>Fix signin URL for UI v2<commit_after>//    Copyright 2017 drillbits
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

const hijack = {};

hijack.getCookie = (nightmare, email, password, fileID, waitMsec) => {
    if (!waitMsec || isNaN(waitMsec)) {
        waitMsec = 3000;
    }
    return nightmare
        .goto('https://accounts.google.com/signin/v2')
        .wait('#identifierId')
        .type('#identifierId', email)
        .click('#identifierNext')
        .wait("input[type=password]")
        .wait(2000) // WORKAROUND
        .type("input[type=password]", password)
        .click('#passwordNext')
        .wait(waitMsec)
        .goto(`https://drive.google.com/file/d/${fileID}/view`)
        .cookies.get('DRIVE_STREAM');
};

hijack.extractStreamMap = (nightmare, fileID, cookie) => {
    return nightmare
        .cookies.set(cookie)
        .goto(`https://drive.google.com/file/d/${fileID}/view`)
        .evaluate(() => {
            const html = document.body.innerHTML,
                s = html.indexOf('_initProjector'),
                e = html.indexOf('</script>', s),
                init = html.slice(s, e),
                streamMap = {};

            const _initProjector = (a, b, c) => {
                return c[19][0][17][1];
            }
            const fmtStreamMap = eval(init);
            fmtStreamMap.split(',').map((x) => {
                const spl = x.split('|');
                const iTag = parseInt(spl[0], 10);
                streamMap[iTag] = spl[1];
            });
            return streamMap;
        });
};

module.exports = hijack;
<|endoftext|>


<commit_before>'use strict';

module.exports = function(grunt) {

    grunt.registerMultiTask("phantomizer-strykejs-builder", "Builds html dependencies of a stryke file", function () {

        var ph_libutil = require("phantomizer-libutil")
        var fs = require("fs")
        var connect = require('connect')
        var http = require('http')

        var childProcess = require('child_process')
        var phantomjs = require('phantomjs')

        var meta_factory = ph_libutil.meta;
        var wd = process.cwd();

        var http_utils = ph_libutil.http_utils;
        var html_utils = ph_libutil.html_utils;
        var file_utils = ph_libutil.file_utils;

        var options = this.options();
        var in_request = options.in_request;
        var port = options.port;
        var ssl_port = options.ssl_port;
        var out_file = options.out;
        var paths = options.paths;
        var meta_file = options.meta;
        var meta_dir = options.meta_dir;
        var current_grunt_task = this.nameArgs;
        var current_grunt_opt = this.options();

        var meta_manager = new meta_factory( wd, meta_dir );

        // check if a cache entry exists, if it is fresh, just serve it
        if( meta_manager.is_fresh(meta_file) == false ){

            var req_logs = {}
            var deps = []

            var target_url = "http://localhost:"+port+in_request;

            var app = connect()
            app.use(connect.query())
            app.use(connect.urlencoded())
            if( options.log == true ){
                app.use(connect.logger('dev'))
            }
            app.use(function(req, res, next){
                var request_path = req.originalUrl
                if( request_path.indexOf("?")>-1){
                    request_path = request_path.substring(0,request_path.indexOf("?"))
                }

                var file = file_utils.find_file(paths,request_path)
                if( file != null ){
                    req_logs[request_path] = file

                    var headers = {
                        'Content-Type': http_utils.header_content_type(file)
                    };
                    var buf = null
                    if( headers["Content-Type"].indexOf("text/") > -1 ){
                        buf = fs.readFileSync(file).toString()
                        if( in_request == request_path ){
                            buf = inject_assets(options, request_path, buf);
                            buf = add_stryke(buf);
                        }
                    }else{
                        buf = fs.readFileSync(file)
                    }
                    res.writeHead(200, headers)
                    res.end(buf)
                }else{
                    next()
                }
            })
            app.use(function(req, res, next){
                var request_path = req.originalUrl;
                if( request_path.indexOf("?")>-1){
                    request_path = request_path.substring(0,request_path.indexOf("?"))
                }
                var file = file_utils.find_dir(paths,request_path)
                if( file != null ){
                    var items = http_utils.merged_dirs(paths, request_path)
                    var buf = ""
                    for(var i in items) {
                        buf += ""+items[i].name+"
"
                    }
                    var headers = {
                        'Content-Type': 'text/html'
                    };
                    res.writeHead(200, headers)
                    res.end(buf)
                }else{
                    next()
                }
            })
            app.use(function(req, res){
                var headers = {
                    'Content-Type': 'text/html'
                };
                res.writeHead(404, headers)
                res.end("not found")
            })

            var wserver = http.createServer(app).listen(port);

            var childArgs = [
                __dirname+'/../ext/phantomjs-stryke-wrapper.js',
                target_url
            ]

            var done = this.async();
            var finish = function(res){
                if( res == true ){
                    grunt.log.ok()
                    done(true);
                }else{
                    grunt.log.error(res)
                    done(false);
                }
            }

            grunt.log.ok("Starting PhantomJS... ")
            childProcess.execFile(phantomjs.path, childArgs, function(err, stdout, stderr) {
                grunt.log.ok("... Done PhantomJS")

                wserver.close();

                if( stderr != "" ){
                    finish("phantomjs error\n"+stderr)
                } else {
                    var retour = extract_html(stdout)
                    // remove stryke configuration used to prevent full execution of the page
                    retour = remove_stryke( retour )
                    // remove requirejs scripts, they are put in the head on runtime
                    retour = remove_rjs_trace( retour )
                    // get traced url call from runtime, remove it from output
                    var trace = extract_stryke_trace( retour )
                    retour = remove_stryke_trace( retour )
                    if( trace.length > 0 ){
                        trace.unshift(in_request)
                        for(var n in trace){
                            deps.push(req_logs[trace[n]])
                        }
                    }
                    // add grunt file to dependencies so that file are rebuild when this file changes
                    deps.push(__filename)
                    if ( grunt.file.exists(process.cwd()+"/Gruntfile.js")) {
                        deps.push(process.cwd()+"/Gruntfile.js")
                    }
                    // create a cache entry, so that later we can regen or check freshness
                    var entry = meta_manager.create(deps)
                    entry.require_task(current_grunt_task, current_grunt_opt)
                    entry.save(meta_file, function(err){
                        if (err) finish(err)
                        else{
                            grunt.file.write(out_file, retour)
                            finish(true)
                        }
                    })
                }
            })

        }else{
            grunt.log.ok("the build is fresh")
        }

        function extract_html( in_str ){
            var wdlm = "\r\n\r\n//-----------//\r\n"
            var dlm = "\n\n//-----------//\n"
            in_str = in_str.replace(wdlm, dlm)
            in_str = in_str.substring( in_str.indexOf(dlm)+dlm.length )
            return in_str
        }
        function add_stryke( in_str ){
            var stryke = ""
            stryke = stryke+""
            in_str = in_str.replace("", stryke+"")
            return in_str
        }
        function remove_stryke( in_str ){
            var stryke = ""
            stryke = stryke+""
            in_str = in_str.replace(stryke+"", "")
            return in_str
        }
        function remove_rjs_trace( in_str ){
            var ptn = /"
            in_str = in_str.replace("", stryke+"")
            return in_str
        }
        function remove_stryke( in_str ){
            var stryke = ""
            stryke = stryke+""
            in_str = in_str.replace(stryke+"", "")
            return in_str
        }
        function remove_rjs_trace( in_str ){
            var ptn = /


<commit_before>const os = require('os');

const { isWebClientLegacy } = require('../config');
const { bash, script } = require('../helpers/cli');
const { debug, info } = require('../helpers/log')('proton-bundler');

const SOURCE_FILE_INDEX = "find dist -maxdepth 1 -type f -name 'index*.js'";

/**
 * Get the configuration for a deployement
 *     [Warning] you must have  NODE_ENV=production
 * @param  {Array} flags flags used to bundle
 * @return {Object}       app's config
 */
async function getNewConfig(flags = process.argv.slice(3), api) {
    if (isWebClientLegacy()) {
        const { stdout = '' } = await bash('./tasks/setupConfig.js', [
            '--print-config',
            `--branch deploy-${api}`,
            ...flags
        ]);
        debug(stdout, 'stdout config angular');
        return JSON.parse(stdout);
    }

    // we don't use npx as for the CI we cached it so it's faster
    const { stdout = '' } = await bash('./node_modules/proton-pack/bin/protonPack print-config', flags);
    debug(stdout, 'stdout config app');
    return JSON.parse(stdout);
}

function sed(rule, files) {
    // Because for the lulz. cf https://myshittycode.com/2014/07/24/os-x-sed-extra-characters-at-the-end-of-l-command-error/
    if (os.platform() === 'darwin') {
        return bash(`sed -i '' '${rule}' $(${files})`);
    }
    return bash(`sed -i '${rule}' "$(${files})"`);
}

async function writeNewConfig() {
    const {
        sentry: { dsn: currentSentryDSN },
        secureUrl: currentSecureURL
    } = await getNewConfig(['--api proxy']);
    const {
        apiUrl,
        sentry: { dsn: newSentryDSN },
        secureUrl: newSecureURL
    } = await getNewConfig();

    if (isWebClientLegacy()) {
        await sed(`s#apiUrl:"/api"#apiUrl:"${apiUrl}"#;`, SOURCE_FILE_INDEX);
        info(`replace current api by ${apiUrl} inside the main index`);

        await sed(`s#sentry:"${currentSentryDSN}"#sentry:"${newSentryDSN}"#;`, SOURCE_FILE_INDEX);
        info('replace sentry config inside the main index');

        await sed(`s#secure:"${currentSecureURL}"#secure:"${newSecureURL}"#;`, SOURCE_FILE_INDEX);
        return info('replace secureURL config inside the main index');
    }

    await sed(`s#="/api"#="${apiUrl}"#;`, SOURCE_FILE_INDEX);
    info(`replace current api by ${apiUrl} inside the main index`);

    await sed(`s#="${currentSentryDSN}"#="${newSentryDSN}"#;`, SOURCE_FILE_INDEX);
    info('replace sentry config inside the main index');

    await sed(`s#="${currentSecureURL}"#="${newSecureURL}"#;`, SOURCE_FILE_INDEX);
    info('replace secureURL config inside the main index');
}

/**
 * Create a new bundle from an existing one
 * To validate the bundle, we use SRI <3 <3 <3 it's easy to validate a new build with them.
 * They crash if it doesn't match <3 <3 <3
 *     - Generate hash for files with the modifications
 *     - Replace them inside index.js
 *     - Then we replace the SRI of index.js inside index.html
 * @return {Promise}
 */
async function main({ api }) {
    await bash('cp -r dist distProd');
    info('made a copy of the current dist');

    await writeNewConfig();

    const { stdout } = await script('manageSRI.sh write-html');
    info('update new index.html');
    debug(stdout, 'write new SRIs HTML');

    const { stdout: stdoutSed } = await script('manageSRI.sh write-env', [api]);
    info('update new .env');
    debug(stdoutSed, 'write new APP_ENV');

    /**
     * Check if the sub-build is valid
     *     - Correct SRI for updated files
     *     - Correct SRI for the index
     *     - Right config for A/B
     *     - Right config for Sentry
     * Stop the process if it fails
     */
    await script('manageSRI.sh validate', [api]);
}

module.exports = main;
<commit_msg>Fix command env WebClient legacy<commit_after>const os = require('os');

const { isWebClientLegacy } = require('../config');
const { bash, script } = require('../helpers/cli');
const { debug, info } = require('../helpers/log')('proton-bundler');

const SOURCE_FILE_INDEX = "find dist -maxdepth 1 -type f -name 'index*.js'";

/**
 * Get the configuration for a deployement
 *     [Warning] you must have  NODE_ENV=production
 * @param  {Array} flags flags used to bundle
 * @return {Object}       app's config
 */
async function getNewConfig(api, flags = process.argv.slice(3)) {
    if (isWebClientLegacy()) {
        const { stdout = '' } = await bash('./tasks/setupConfig.js', [
            '--print-config',
            `--branch deploy-${api.replace('+proxy', '')}`,
            ...flags
        ]);
        debug(stdout, 'stdout config angular');
        return JSON.parse(stdout);
    }

    // we don't use npx as for the CI we cached it so it's faster
    const { stdout = '' } = await bash('./node_modules/proton-pack/bin/protonPack print-config', flags);
    debug(stdout, 'stdout config app');
    return JSON.parse(stdout);
}

function sed(rule, files) {
    // Because for the lulz. cf https://myshittycode.com/2014/07/24/os-x-sed-extra-characters-at-the-end-of-l-command-error/
    if (os.platform() === 'darwin') {
        return bash(`sed -i '' '${rule}' $(${files})`);
    }
    return bash(`sed -i '${rule}' "$(${files})"`);
}

async function writeNewConfig(api) {
    const {
        sentry: { dsn: currentSentryDSN },
        secureUrl: currentSecureURL
    } = await getNewConfig(api, ['--api proxy']);
    const {
        apiUrl,
        sentry: { dsn: newSentryDSN },
        secureUrl: newSecureURL
    } = await getNewConfig(api);

    if (isWebClientLegacy()) {
        await sed(`s#apiUrl:"/api"#apiUrl:"${apiUrl}"#;`, SOURCE_FILE_INDEX);
        info(`replace current api by ${apiUrl} inside the main index`);

        await sed(`s#sentry:"${currentSentryDSN}"#sentry:"${newSentryDSN}"#;`, SOURCE_FILE_INDEX);
        info('replace sentry config inside the main index');

        await sed(`s#secure:"${currentSecureURL}"#secure:"${newSecureURL}"#;`, SOURCE_FILE_INDEX);
        return info('replace secureURL config inside the main index');
    }

    await sed(`s#="/api"#="${apiUrl}"#;`, SOURCE_FILE_INDEX);
    info(`replace current api by ${apiUrl} inside the main index`);

    await sed(`s#="${currentSentryDSN}"#="${newSentryDSN}"#;`, SOURCE_FILE_INDEX);
    info('replace sentry config inside the main index');

    await sed(`s#="${currentSecureURL}"#="${newSecureURL}"#;`, SOURCE_FILE_INDEX);
    info('replace secureURL config inside the main index');
}

/**
 * Create a new bundle from an existing one
 * To validate the bundle, we use SRI <3 <3 <3 it's easy to validate a new build with them.
 * They crash if it doesn't match <3 <3 <3
 *     - Generate hash for files with the modifications
 *     - Replace them inside index.js
 *     - Then we replace the SRI of index.js inside index.html
 * @return {Promise}
 */
async function main({ api }) {
    await bash('cp -r dist distProd');
    info('made a copy of the current dist');

    await writeNewConfig(api);

    const { stdout } = await script('manageSRI.sh write-html');
    info('update new index.html');
    debug(stdout, 'write new SRIs HTML');

    const { stdout: stdoutSed } = await script('manageSRI.sh write-env', [api]);
    info('update new .env');
    debug(stdoutSed, 'write new APP_ENV');

    /**
     * Check if the sub-build is valid
     *     - Correct SRI for updated files
     *     - Correct SRI for the index
     *     - Right config for A/B
     *     - Right config for Sentry
     * Stop the process if it fails
     */
    await script('manageSRI.sh validate', [api]);
}

module.exports = main;
<|endoftext|>


<commit_before>/**
 * @file Notification component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import IconButton from '../IconButton';
import AnchorButton from '../AnchorButton';

import Util from '../_vendors/Util';
import MsgType from '../_statics/MsgType';

class Notification extends Component {

    static Type = MsgType;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.hasMounted = false;
        this.unrenderTimeout = null;

        this.state = {
            hidden: true,
            leave: false
        };

        this.getIconCls = ::this.getIconCls;
        this.touchTapHandler = ::this.touchTapHandler;
        this.initializeAnimation = ::this.initializeAnimation;
        this.animate = ::this.animate;

    }

    getIconCls() {
        switch (this.props.type) {
            case MsgType.SUCCESS:
                return 'fa fa-check-circle';
            case MsgType.WARNING:
                return 'fa fa-exclamation-triangle';
            case MsgType.ERROR:
                return 'fa fa-times-circle';
            default:
                return 'fa fa-info-circle';
        }
    }

    touchTapHandler(e) {
        e.preventDefault();
        const {onRequestClose, notificationId} = this.props;
        onRequestClose && onRequestClose(notificationId);
    }

    initializeAnimation(callback) {
        setTimeout(() => {
            this.hasMounted && callback();
        }, 0);
    }

    animate() {
        this.setState({
            hidden: false
        });
    }

    componentDidMount() {

        const {notificationId, duration, onRequestClose} = this.props;

        this.hasMounted = true;

        const notificationEl = this.refs.notification;
        notificationEl.style.height = notificationEl.clientHeight + 'px';
        notificationEl.style.width = notificationEl.clientWidth + 'px';

        duration > 0 && (this.unrenderTimeout = setTimeout(() => {
            onRequestClose && onRequestClose(notificationId);
        }, duration));

    }

    componentWillAppear(callback) {
        this.initializeAnimation(callback);
    }

    componentWillEnter(callback) {
        this.initializeAnimation(callback);
    }

    componentDidAppear() {
        this.animate();
    }

    componentDidEnter() {
        this.animate();
    }

    componentWillLeave(callback) {
        this.setState({
            hidden: true,
            leave: true
        }, () => {
            this.unrenderTimeout = setTimeout(() => {
                this.hasMounted && callback();
            }, 500);
        });
    }

    componentWillUnmount() {
        this.unrenderTimeout && clearTimeout(this.unrenderTimeout);
    }

    render() {

        const {
                className, style, type, title, message, iconCls,
                closeIconVisible, closeButtonVisible, closeButtonValue
            } = this.props,
            {hidden, leave} = this.state,

            wrapperClassName = ` theme-${type}` + (hidden ? ' hidden' : '') + (leave ? ' leave' : '')
                + (closeButtonVisible ? ' has-close-button' : '') + (className ? ' ' + className : '');

        return (

                <i className={`${iconCls ? iconCls : this.getIconCls()} notification-icon`}>

{title}

                    {message}

                {
                    closeIconVisible ?
                        <IconButton className="notification-close-icon"
                                    iconCls="fa fa-times"
                                    onTouchTap={this.touchTapHandler}/>
                        :
                        null
                }

                {
                    closeButtonVisible ?
                        <AnchorButton className="notification-close-Button"
                                      value={closeButtonValue}
                                      onTouchTap={this.touchTapHandler}/>
                        :
                        null
                }

        );

    }
};

Notification.propTypes = {

    /**
     * The CSS class name of notification.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the notification.
     */
    style: PropTypes.object,

    notificationId: PropTypes.number,

    /**
     * The type of notification.
     */
    type: PropTypes.oneOf(Util.enumerateValue(MsgType)),

    /**
     * The title of notification.
     */
    title: PropTypes.any,

    /**
     * The message of notification.
     */
    message: PropTypes.any,

    /**
     * The icon class name of notification.
     */
    iconCls: PropTypes.string,

    /**
     * The duration of notification.
     */
    duration: PropTypes.number,

    closeIconVisible: PropTypes.bool,
    closeButtonVisible: PropTypes.bool,
    closeButtonValue: PropTypes.string,

    onRequestClose: PropTypes.func

};

Notification.defaultProps = {

    className: '',
    style: null,

    notificationId: 0,
    type: MsgType.INFO,
    title: 'message',
    message: '',
    iconCls: '',
    duration: 0,

    closeIconVisible: false,
    closeButtonVisible: true,
    closeButtonValue: 'Close'

};

export default Notification;<commit_msg>update Notification<commit_after>/**
 * @file Notification component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import IconButton from '../IconButton';
import AnchorButton from '../AnchorButton';

import Util from '../_vendors/Util';
import MsgType from '../_statics/MsgType';

class Notification extends Component {

    static Type = MsgType;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.hasMounted = false;
        this.unrenderTimeout = null;

        this.state = {
            hidden: true,
            leave: false
        };

        this.getIconCls = ::this.getIconCls;
        this.touchTapHandler = ::this.touchTapHandler;
        this.initializeAnimation = ::this.initializeAnimation;
        this.animate = ::this.animate;

    }

    getIconCls() {
        switch (this.props.type) {
            case MsgType.SUCCESS:
                return 'fa fa-check-circle';
            case MsgType.WARNING:
                return 'fa fa-exclamation-triangle';
            case MsgType.ERROR:
                return 'fa fa-times-circle';
            default:
                return 'fa fa-info-circle';
        }
    }

    touchTapHandler(e) {
        e.preventDefault();
        const {onRequestClose, notificationId} = this.props;
        onRequestClose && onRequestClose(notificationId);
    }

    initializeAnimation(callback) {
        setTimeout(() => {
            this.hasMounted && callback();
        }, 0);
    }

    animate() {
        this.setState({
            hidden: false
        });
    }

    componentDidMount() {

        const {notificationId, duration, onRequestClose} = this.props;

        this.hasMounted = true;

        const notificationEl = this.refs.notification;
        notificationEl.style.height = notificationEl.clientHeight + 'px';
        notificationEl.style.width = notificationEl.clientWidth + 'px';

        duration > 0 && (this.unrenderTimeout = setTimeout(() => {
            onRequestClose && onRequestClose(notificationId);
        }, duration));

    }

    componentWillAppear(callback) {
        this.initializeAnimation(callback);
    }

    componentWillEnter(callback) {
        this.initializeAnimation(callback);
    }

    componentDidAppear() {
        this.animate();
    }

    componentDidEnter() {
        this.animate();
    }

    componentWillLeave(callback) {
        this.setState({
            hidden: true,
            leave: true
        }, () => {
            this.unrenderTimeout = setTimeout(() => {
                this.hasMounted && callback();
            }, 500);
        });
    }

    componentWillUnmount() {
        this.unrenderTimeout && clearTimeout(this.unrenderTimeout);
    }

    render() {

        const {
                className, style, type, title, message, iconCls,
                closeIconVisible, closeButtonVisible, closeButtonValue
            } = this.props,
            {hidden, leave} = this.state,

            wrapperClassName = classNames('notification', `theme-${type}`, {
                hidden: hidden,
                leave: leave,
                'has-close-button': closeButtonVisible,
                [className]: className
            });

        return (

                <i className={`${iconCls ? iconCls : this.getIconCls()} notification-icon`}>

{title}

                    {message}

                {
                    closeIconVisible ?
                        <IconButton className="notification-close-icon"
                                    iconCls="fa fa-times"
                                    onTouchTap={this.touchTapHandler}/>
                        :
                        null
                }

                {
                    closeButtonVisible ?
                        <AnchorButton className="notification-close-Button"
                                      value={closeButtonValue}
                                      onTouchTap={this.touchTapHandler}/>
                        :
                        null
                }

        );

    }
};

Notification.propTypes = {

    /**
     * The CSS class name of notification.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the notification.
     */
    style: PropTypes.object,

    notificationId: PropTypes.number,

    /**
     * The type of notification.
     */
    type: PropTypes.oneOf(Util.enumerateValue(MsgType)),

    /**
     * The title of notification.
     */
    title: PropTypes.any,

    /**
     * The message of notification.
     */
    message: PropTypes.any,

    /**
     * The icon class name of notification.
     */
    iconCls: PropTypes.string,

    /**
     * The duration of notification.
     */
    duration: PropTypes.number,

    closeIconVisible: PropTypes.bool,
    closeButtonVisible: PropTypes.bool,
    closeButtonValue: PropTypes.string,

    onRequestClose: PropTypes.func

};

Notification.defaultProps = {

    className: '',
    style: null,

    notificationId: 0,
    type: MsgType.INFO,
    title: 'message',
    message: '',
    iconCls: '',
    duration: 0,

    closeIconVisible: false,
    closeButtonVisible: true,
    closeButtonValue: 'Close'

};

export default Notification;<|endoftext|>