<commit_before>/* global Talkilla, Backbone, _, jQuery*/
/**
 * Talkilla Backbone views.
 */
(function(app, Backbone, _, $) {
  "use strict";

  /**
   * Global app view.
   */
  app.views.AppView = Backbone.View.extend({
    el: 'body',

    data: {},

    viewClasses: {
      call:  'CallView',
      login: 'LoginView',
      users: 'UsersView'
    },

    views: {},

    initialize: function(options) {
      this.data = options && options.data || this.data;
      // events
      app.on('signout', function() {
        this.views.call.hangup();
      }.bind(this));
      this.update();
    },

    update: function(data) {
      this.data = data || {};
      for (var name in this.viewClasses) {
        var ViewClass = app.views[this.viewClasses[name]];
        if (name in this.views)
          this.views[name].undelegateEvents();
        this.views[name] = new ViewClass(this.data);
      }
      this.render();
    },

    render: function() {
      for (var name in this.views) {
        var view = this.views[name];
        if (!view)
          continue;
        view.render();
      }
    }
  });

  /**
   * User list entry view.
   */
  app.views.UserEntryView = Backbone.View.extend({
    tagName: 'li',

    render: function() {
      var nick = this.model.get('nick');
      this.$el.html(
        '' + nick + '');
      return this;
    }
  });

  /**
   * User list view.
   */
  app.views.UsersView = Backbone.View.extend({
    el: '#users',

    views: [],

    initViews: function() {
      this.views = [];
      this.collection.each(function(model) {
        this.views.push(new app.views.UserEntryView({model: model}));
      }.bind(this));
    },

    initialize: function(options) {
      this.collection = options && options.users;
      if (this.collection) {
        this.initViews();
        return this.render();
      }
      this.collection = new app.models.UserSet();
      this.collection.fetch({
        error: function() {
          app.utils.notifyUI('Could not load connected users list', 'error');
        },
        success: function() {
          this.initViews();
          this.render();
        }.bind(this)
      });
    },

    render: function() {
      var userList = _.chain(this.views).map(function(view) {
        return view.render();
      }).pluck('el').value();
      this.$('li:not(.nav-header)').remove();
      this.$('ul').append(userList);
      if (app.data.user && this.collection.length === 0)
        this.$('#invite').show();
      else
        this.$('#invite').hide();
      return this;
    }
  });

  /**
   * Login/logout forms view.
   */
  app.views.LoginView = Backbone.View.extend({
    el: '#login',

    events: {
      'submit form#signin': 'signin',
      'submit form#signout': 'signout'
    },

    initialize: function(options) {
      this.user = options && options.user;
    },

    render: function() {
      if (!this.user) {
        this.$('#signin').show();
        this.$('#signout').hide().find('.nick').text('');
      } else {
        this.$('#signin').hide();
        this.$('#signout').show().find('.nick').text(this.user.get('nick'));
      }
      return this;
    },

    signin: function(event) {
      event.preventDefault();
      var nick = $.trim($(event.currentTarget).find('[name="nick"]').val());
      if (!nick)
        return app.utils.notifyUI('please enter a nickname');
      app.services.login(nick, function(err, user, users) {
        if (err)
          return app.utils.notifyUI(err, 'error');
        app.data.user = user;
        app.data.users = users;
        app.trigger('signin', user);
        app.router.navigate('', {trigger: true});
        app.router.index();
      });
    },

    signout: function(event) {
      event.preventDefault();
      app.services.logout(function(err) {
        if (err)
          return app.utils.notifyUI(err, 'error');
        delete app.data.callee;
        delete app.data.user;
        app.trigger('signout');
        app.router.navigate('', {trigger: true});
        app.router.index();
      });
    }
  });

  /**
   * Main video conversation view.
   */
  app.views.CallView = Backbone.View.extend({
    el: '#call',

    local: undefined,

    events: {
      'click .btn-initiate': 'initiate',
      'click .btn-hangup':   'hangup'
    },

    initialize: function(options) {
      this.hangup();
      this.user = options && options.user;
      this.callee = options && options.callee;
      this.local = $('#local-video').get(0);
    },

    initiate: function() {
      // TODO:
      // - extract the processus to some external lib?
      // - handle asynchronicity (events?)
      navigator.mozGetUserMedia(
        {video: true, audio: true},

        function onSuccess(stream) {
          app.utils.log('local video enabled');
          this.local.mozSrcObject = stream;
          this.local.play();
          this.$('.btn-initiate').addClass('disabled');
          this.$('.btn-hangup').removeClass('disabled');
        }.bind(this),

        function onError(err) {
          app.utils.log(err);
          app.utils.notifyUI('Impossible to access your webcam/microphone',
                             'error');
        });
    },

    hangup: function() {
      if (this.local && this.local.mozSrcObject) {
        this.local.mozSrcObject.stop();
        this.local.mozSrcObject = null;
      }
      this.$('.btn-initiate').removeClass('disabled');
      this.$('.btn-hangup').addClass('disabled');
    },

    render: function() {
      if (!this.callee) {
        this.$el.hide();
        return this;
      }
      this.$('h2').text('Calling ' + this.callee.get('nick'));
      this.initiate();
      this.$el.show();
      return this;
    }
  });
})(Talkilla, Backbone, _, jQuery);
<commit_msg>moved 'hangup on signout' event listener to CallView<commit_after>/* global Talkilla, Backbone, _, jQuery*/
/**
 * Talkilla Backbone views.
 */
(function(app, Backbone, _, $) {
  "use strict";

  /**
   * Global app view.
   */
  app.views.AppView = Backbone.View.extend({
    el: 'body',

    data: {},

    viewClasses: {
      call:  'CallView',
      login: 'LoginView',
      users: 'UsersView'
    },

    views: {},

    initialize: function(options) {
      this.data = options && options.data || this.data;
      this.update();
    },

    update: function(data) {
      this.data = data || {};
      for (var name in this.viewClasses) {
        var ViewClass = app.views[this.viewClasses[name]];
        if (name in this.views)
          this.views[name].undelegateEvents();
        this.views[name] = new ViewClass(this.data);
      }
      this.render();
    },

    render: function() {
      for (var name in this.views) {
        var view = this.views[name];
        if (!view)
          continue;
        view.render();
      }
    }
  });

  /**
   * User list entry view.
   */
  app.views.UserEntryView = Backbone.View.extend({
    tagName: 'li',

    render: function() {
      var nick = this.model.get('nick');
      this.$el.html(
        '' + nick + '');
      return this;
    }
  });

  /**
   * User list view.
   */
  app.views.UsersView = Backbone.View.extend({
    el: '#users',

    views: [],

    initViews: function() {
      this.views = [];
      this.collection.each(function(model) {
        this.views.push(new app.views.UserEntryView({model: model}));
      }.bind(this));
    },

    initialize: function(options) {
      this.collection = options && options.users;
      if (this.collection) {
        this.initViews();
        return this.render();
      }
      this.collection = new app.models.UserSet();
      this.collection.fetch({
        error: function() {
          app.utils.notifyUI('Could not load connected users list', 'error');
        },
        success: function() {
          this.initViews();
          this.render();
        }.bind(this)
      });
    },

    render: function() {
      var userList = _.chain(this.views).map(function(view) {
        return view.render();
      }).pluck('el').value();
      this.$('li:not(.nav-header)').remove();
      this.$('ul').append(userList);
      if (app.data.user && this.collection.length === 0)
        this.$('#invite').show();
      else
        this.$('#invite').hide();
      return this;
    }
  });

  /**
   * Login/logout forms view.
   */
  app.views.LoginView = Backbone.View.extend({
    el: '#login',

    events: {
      'submit form#signin': 'signin',
      'submit form#signout': 'signout'
    },

    initialize: function(options) {
      this.user = options && options.user;
    },

    render: function() {
      if (!this.user) {
        this.$('#signin').show();
        this.$('#signout').hide().find('.nick').text('');
      } else {
        this.$('#signin').hide();
        this.$('#signout').show().find('.nick').text(this.user.get('nick'));
      }
      return this;
    },

    signin: function(event) {
      event.preventDefault();
      var nick = $.trim($(event.currentTarget).find('[name="nick"]').val());
      if (!nick)
        return app.utils.notifyUI('please enter a nickname');
      app.services.login(nick, function(err, user, users) {
        if (err)
          return app.utils.notifyUI(err, 'error');
        app.data.user = user;
        app.data.users = users;
        app.trigger('signin', user);
        app.router.navigate('', {trigger: true});
        app.router.index();
      });
    },

    signout: function(event) {
      event.preventDefault();
      app.services.logout(function(err) {
        if (err)
          return app.utils.notifyUI(err, 'error');
        delete app.data.callee;
        delete app.data.user;
        app.trigger('signout');
        app.router.navigate('', {trigger: true});
        app.router.index();
      });
    }
  });

  /**
   * Main video conversation view.
   */
  app.views.CallView = Backbone.View.extend({
    el: '#call',

    local: undefined,

    events: {
      'click .btn-initiate': 'initiate',
      'click .btn-hangup':   'hangup'
    },

    initialize: function(options) {
      this.hangup();
      this.user = options && options.user;
      this.callee = options && options.callee;
      this.local = $('#local-video').get(0);
      // app events
      app.on('signout', function() {
        // ensure a call is always terminated on user signout
        this.hangup();
      }.bind(this));
    },

    initiate: function() {
      // TODO:
      // - extract the processus to some external lib?
      // - handle asynchronicity (events?)
      navigator.mozGetUserMedia(
        {video: true, audio: true},

        function onSuccess(stream) {
          app.utils.log('local video enabled');
          this.local.mozSrcObject = stream;
          this.local.play();
          this.$('.btn-initiate').addClass('disabled');
          this.$('.btn-hangup').removeClass('disabled');
        }.bind(this),

        function onError(err) {
          app.utils.log(err);
          app.utils.notifyUI('Impossible to access your webcam/microphone',
                             'error');
        });
    },

    hangup: function() {
      if (this.local && this.local.mozSrcObject) {
        this.local.mozSrcObject.stop();
        this.local.mozSrcObject = null;
      }
      this.$('.btn-initiate').removeClass('disabled');
      this.$('.btn-hangup').addClass('disabled');
    },

    render: function() {
      if (!this.callee) {
        this.$el.hide();
        return this;
      }
      this.$('h2').text('Calling ' + this.callee.get('nick'));
      this.initiate();
      this.$el.show();
      return this;
    }
  });
})(Talkilla, Backbone, _, jQuery);
<|endoftext|>


<commit_before>/*
 * angucomplete-alt
 * Autocomplete directive for AngularJS
 * This is a fork of Daryl Rowland's angucomplete with some extra features.
 * By Hidenari Nozaki
 *
 * Copyright (c) 2014 Hidenari Nozaki and contributors
 * Licensed under the MIT license
 */

'use strict';

angular.module('angucomplete-alt', [] ).directive('angucompleteAlt', ['$parse', '$http', '$sce', '$timeout', function ($parse, $http, $sce, $timeout) {
  var KEY_DW = 40,
      KEY_UP = 38,
      KEY_ES = 27,
      KEY_EN = 13,
      KEY_BS =  8,
      KEY_DEL =  46,
      MIN_LENGTH = 3,
      PAUSE = 500;

  return {
    restrict: 'EA',
    scope: {
      selectedObject: '=',
      localData: '=',
      remoteUrlRequestFormatter: '=',
      id: '@',
      placeholder: '@',
      remoteUrl: '@',
      remoteUrlDataField: '@',
      titleField: '@',
      descriptionField: '@',
      imageField: '@',
      inputClass: '@',
      pause: '@',
      searchFields: '@',
      minlength: '@',
      matchClass: '@',
      clearSelected: '@',
      overrideSuggestions: '@'
    },
    template: '
<input id="{{id}}_value" ng-model="searchStr" type="text" placeholder="{{placeholder}}" class="{{inputClass}}" ng-focus="resetHideResults()" ng-blur="hideResults()"/>

Searching...

No results found

{{ result.title }}

{{result.description}}

',
    link: function(scope, elem, attrs) {
      var inputField,
          minlength = MIN_LENGTH,
          searchTimer = null,
          lastSearchTerm = null,
          hideTimer;

      scope.currentIndex = null;
      scope.searching = false;
      scope.searchStr = null;

      var setInputString = function(str) {
        scope.selectedObject = {originalObject: str};

        if (scope.clearSelected) {
          scope.searchStr = null;
        }
        scope.showDropdown = false;
        scope.results = [];
      };

      var isNewSearchNeeded = function(newTerm, oldTerm) {
        return newTerm.length >= minlength && newTerm !== oldTerm;
      };

      var extractValue = function(obj, key) {
        var keys, result;
        if (key) {
          keys= key.split('.');
          result = obj;
          keys.forEach(function(k) { result = result[k]; });
        }
        else {
          result = obj;
        }
        return result;
      };

      if (scope.minlength && scope.minlength !== '') {
        minlength = scope.minlength;
      }

      if (!scope.pause) {
        scope.pause = PAUSE;
      }

      if (!scope.clearSelected) {
        scope.clearSelected = false;
      }

      if (!scope.overrideSuggestions) {
        scope.overrideSuggestions = false;
      }

      scope.hideResults = function() {
        hideTimer = $timeout(function() {
          scope.showDropdown = false;
        }, scope.pause);
      };

      scope.resetHideResults = function() {
        if (hideTimer) {
          $timeout.cancel(hideTimer);
        }
      };

      scope.processResults = function(responseData, str) {
        var titleFields, titleCode, i, t, description, image, text, re, strPart, matches;

        if (responseData && responseData.length > 0) {
          scope.results = [];

          titleFields = [];
          if (scope.titleField && scope.titleField !== '') {
            titleFields = scope.titleField.split(',');
          }

          for (i = 0; i < responseData.length; i++) {
            // Get title variables
            titleCode = [];

            for (t = 0; t < titleFields.length; t++) {
              titleCode.push(responseData[i][titleFields[t]]);
            }

            description = '';
            if (scope.descriptionField) {
              description = extractValue(responseData[i], scope.descriptionField);
            }

            image = '';
            if (scope.imageField) {
              image = extractValue(responseData[i], scope.imageField);
            }

            text = titleCode.join(' ');
            if (scope.matchClass) {
              re = new RegExp(str, 'i');
              matches = text.match(re);
              if (matches) {
                strPart = matches[0];
                text = $sce.trustAsHtml(text.replace(re, ''+ strPart +''));
              }
              else {
                text = $sce.trustAsHtml(text);
              }
            }

            scope.results[scope.results.length] = {
              title: text,
              description: description,
              image: image,
              originalObject: responseData[i]
            };

          }

        } else {
          scope.results = [];
        }
      };

      scope.searchTimerComplete = function(str) {
        // Begin the search
        var searchFields, matches, i, match, s, params;

        if (str.length >= minlength) {
          if (scope.localData) {
            searchFields = scope.searchFields.split(',');

            matches = [];

            for (i = 0; i < scope.localData.length; i++) {
              match = false;

              for (s = 0; s < searchFields.length; s++) {
                match = match || (scope.localData[i][searchFields[s]].toLowerCase().indexOf(str.toLowerCase()) >= 0);
              }

              if (match) {
                matches[matches.length] = scope.localData[i];
              }
            }

            scope.searching = false;
            scope.processResults(matches, str);

          } else if (scope.remoteUrlRequestFormatter) {
            params = scope.remoteUrlRequestFormatter(str);
            $http.get(scope.remoteUrl, {params: params}).
              success(function(responseData, status, headers, config) {
                scope.searching = false;
                scope.processResults(extractValue(responseData, scope.remoteUrlDataField), str);
              }).
            error(function(data, status, headers, config) {
              console.log('error');
            });

          } else {
            $http.get(scope.remoteUrl + str, {}).
              success(function(responseData, status, headers, config) {
                scope.searching = false;
                scope.processResults(extractValue(responseData, scope.remoteUrlDataField), str);
              }).
            error(function(data, status, headers, config) {
              console.log('error');
            });
          }
        }

      };

      scope.hoverRow = function(index) {
        scope.currentIndex = index;
      };

      scope.keyPressed = function(event) {
        if (!(event.which === KEY_UP || event.which === KEY_DW || event.which === KEY_EN)) {
          if (!scope.searchStr || scope.searchStr === '') {
            scope.showDropdown = false;
            lastSearchTerm = null;
          } else if (isNewSearchNeeded(scope.searchStr, lastSearchTerm)) {
            lastSearchTerm = scope.searchStr;
            scope.showDropdown = true;
            scope.currentIndex = -1;
            scope.results = [];

            if (searchTimer) {
              $timeout.cancel(searchTimer);
            }

            scope.searching = true;

            searchTimer = $timeout(function() {
              scope.searchTimerComplete(scope.searchStr);
            }, scope.pause);
          }
        } else {
          event.preventDefault();
        }
      };

      scope.selectResult = function(result) {
        if (scope.matchClass) {
          result.title = result.title.toString().replace(/(<([^>]+)>)/ig, '');
        }

        if (scope.clearSelected) {
          scope.searchStr = null;
        }
        else {
          scope.searchStr = lastSearchTerm = result.title;
        }
        scope.selectedObject = result;
        scope.showDropdown = false;
        scope.results = [];
      };

      inputField = elem.find('input');

      inputField.on('keyup', scope.keyPressed);

      elem.on('keyup', function (event) {
        if(event.which === KEY_DW && scope.results) {
          if ((scope.currentIndex + 1) < scope.results.length) {
            scope.$apply(function() {
              scope.currentIndex ++;
            });
            event.preventDefault();
          }

        } else if(event.which === KEY_UP) {
          if (scope.currentIndex >= 1) {
            scope.currentIndex --;
            scope.$apply();
            event.preventDefault();
          }

        } else if (event.which === KEY_EN && scope.results) {
          if (scope.currentIndex >= 0 && scope.currentIndex < scope.results.length) {
            scope.selectResult(scope.results[scope.currentIndex]);
            scope.$apply();
            event.preventDefault();
          } else {
            event.preventDefault();
            if (scope.overrideSuggestions) {
              setInputString(scope.searchStr);
              scope.$apply();
            }
            else {
              scope.results = [];
              scope.$apply();
            }
          }

        } else if (event.which === KEY_ES) {
          scope.results = [];
          scope.showDropdown = false;
          scope.$apply();
        } else if (event.which === KEY_BS || event.which === KEY_DEL) {
          scope.selectedObject = null;
          scope.$apply();
        }
      });
    }
  };
}]);

<commit_msg>Better template format by @nekcih proposed in #6<commit_after>/*
 * angucomplete-alt
 * Autocomplete directive for AngularJS
 * This is a fork of Daryl Rowland's angucomplete with some extra features.
 * By Hidenari Nozaki
 *
 * Copyright (c) 2014 Hidenari Nozaki and contributors
 * Licensed under the MIT license
 */

'use strict';

angular.module('angucomplete-alt', [] ).directive('angucompleteAlt', ['$parse', '$http', '$sce', '$timeout', function ($parse, $http, $sce, $timeout) {
  var KEY_DW = 40,
      KEY_UP = 38,
      KEY_ES = 27,
      KEY_EN = 13,
      KEY_BS =  8,
      KEY_DEL =  46,
      MIN_LENGTH = 3,
      PAUSE = 500;

  return {
    restrict: 'EA',
    scope: {
      selectedObject: '=',
      localData: '=',
      remoteUrlRequestFormatter: '=',
      id: '@',
      placeholder: '@',
      remoteUrl: '@',
      remoteUrlDataField: '@',
      titleField: '@',
      descriptionField: '@',
      imageField: '@',
      inputClass: '@',
      pause: '@',
      searchFields: '@',
      minlength: '@',
      matchClass: '@',
      clearSelected: '@',
      overrideSuggestions: '@'
    },
    template:
      '
' +
      '  <input id="{{id}}_value" ng-model="searchStr" type="text" placeholder="{{placeholder}}" class="{{inputClass}}" ng-focus="resetHideResults()" ng-blur="hideResults()"/>' +
      '
' +
      '
Searching...
' +
      '
No results found
' +
      '
' +
      '
' +
      '        ' +
      '

' +
      '
' +
      '

' +
      '
{{ result.title }}
' +
      '
{{result.description}}
' +
      '
' +
      '
' +
      '
',
    link: function(scope, elem, attrs) {
      var inputField,
          minlength = MIN_LENGTH,
          searchTimer = null,
          lastSearchTerm = null,
          hideTimer;

      scope.currentIndex = null;
      scope.searching = false;
      scope.searchStr = null;

      var setInputString = function(str) {
        scope.selectedObject = {originalObject: str};

        if (scope.clearSelected) {
          scope.searchStr = null;
        }
        scope.showDropdown = false;
        scope.results = [];
      };

      var isNewSearchNeeded = function(newTerm, oldTerm) {
        return newTerm.length >= minlength && newTerm !== oldTerm;
      };

      var extractValue = function(obj, key) {
        var keys, result;
        if (key) {
          keys= key.split('.');
          result = obj;
          keys.forEach(function(k) { result = result[k]; });
        }
        else {
          result = obj;
        }
        return result;
      };

      if (scope.minlength && scope.minlength !== '') {
        minlength = scope.minlength;
      }

      if (!scope.pause) {
        scope.pause = PAUSE;
      }

      if (!scope.clearSelected) {
        scope.clearSelected = false;
      }

      if (!scope.overrideSuggestions) {
        scope.overrideSuggestions = false;
      }

      scope.hideResults = function() {
        hideTimer = $timeout(function() {
          scope.showDropdown = false;
        }, scope.pause);
      };

      scope.resetHideResults = function() {
        if (hideTimer) {
          $timeout.cancel(hideTimer);
        }
      };

      scope.processResults = function(responseData, str) {
        var titleFields, titleCode, i, t, description, image, text, re, strPart, matches;

        if (responseData && responseData.length > 0) {
          scope.results = [];

          titleFields = [];
          if (scope.titleField && scope.titleField !== '') {
            titleFields = scope.titleField.split(',');
          }

          for (i = 0; i < responseData.length; i++) {
            // Get title variables
            titleCode = [];

            for (t = 0; t < titleFields.length; t++) {
              titleCode.push(responseData[i][titleFields[t]]);
            }

            description = '';
            if (scope.descriptionField) {
              description = extractValue(responseData[i], scope.descriptionField);
            }

            image = '';
            if (scope.imageField) {
              image = extractValue(responseData[i], scope.imageField);
            }

            text = titleCode.join(' ');
            if (scope.matchClass) {
              re = new RegExp(str, 'i');
              matches = text.match(re);
              if (matches) {
                strPart = matches[0];
                text = $sce.trustAsHtml(text.replace(re, ''+ strPart +''));
              }
              else {
                text = $sce.trustAsHtml(text);
              }
            }

            scope.results[scope.results.length] = {
              title: text,
              description: description,
              image: image,
              originalObject: responseData[i]
            };

          }

        } else {
          scope.results = [];
        }
      };

      scope.searchTimerComplete = function(str) {
        // Begin the search
        var searchFields, matches, i, match, s, params;

        if (str.length >= minlength) {
          if (scope.localData) {
            searchFields = scope.searchFields.split(',');

            matches = [];

            for (i = 0; i < scope.localData.length; i++) {
              match = false;

              for (s = 0; s < searchFields.length; s++) {
                match = match || (scope.localData[i][searchFields[s]].toLowerCase().indexOf(str.toLowerCase()) >= 0);
              }

              if (match) {
                matches[matches.length] = scope.localData[i];
              }
            }

            scope.searching = false;
            scope.processResults(matches, str);

          } else if (scope.remoteUrlRequestFormatter) {
            params = scope.remoteUrlRequestFormatter(str);
            $http.get(scope.remoteUrl, {params: params}).
              success(function(responseData, status, headers, config) {
                scope.searching = false;
                scope.processResults(extractValue(responseData, scope.remoteUrlDataField), str);
              }).
            error(function(data, status, headers, config) {
              console.log('error');
            });

          } else {
            $http.get(scope.remoteUrl + str, {}).
              success(function(responseData, status, headers, config) {
                scope.searching = false;
                scope.processResults(extractValue(responseData, scope.remoteUrlDataField), str);
              }).
            error(function(data, status, headers, config) {
              console.log('error');
            });
          }
        }

      };

      scope.hoverRow = function(index) {
        scope.currentIndex = index;
      };

      scope.keyPressed = function(event) {
        if (!(event.which === KEY_UP || event.which === KEY_DW || event.which === KEY_EN)) {
          if (!scope.searchStr || scope.searchStr === '') {
            scope.showDropdown = false;
            lastSearchTerm = null;
          } else if (isNewSearchNeeded(scope.searchStr, lastSearchTerm)) {
            lastSearchTerm = scope.searchStr;
            scope.showDropdown = true;
            scope.currentIndex = -1;
            scope.results = [];

            if (searchTimer) {
              $timeout.cancel(searchTimer);
            }

            scope.searching = true;

            searchTimer = $timeout(function() {
              scope.searchTimerComplete(scope.searchStr);
            }, scope.pause);
          }
        } else {
          event.preventDefault();
        }
      };

      scope.selectResult = function(result) {
        if (scope.matchClass) {
          result.title = result.title.toString().replace(/(<([^>]+)>)/ig, '');
        }

        if (scope.clearSelected) {
          scope.searchStr = null;
        }
        else {
          scope.searchStr = lastSearchTerm = result.title;
        }
        scope.selectedObject = result;
        scope.showDropdown = false;
        scope.results = [];
      };

      inputField = elem.find('input');

      inputField.on('keyup', scope.keyPressed);

      elem.on('keyup', function (event) {
        if(event.which === KEY_DW && scope.results) {
          if ((scope.currentIndex + 1) < scope.results.length) {
            scope.$apply(function() {
              scope.currentIndex ++;
            });
            event.preventDefault();
          }

        } else if(event.which === KEY_UP) {
          if (scope.currentIndex >= 1) {
            scope.currentIndex --;
            scope.$apply();
            event.preventDefault();
          }

        } else if (event.which === KEY_EN && scope.results) {
          if (scope.currentIndex >= 0 && scope.currentIndex < scope.results.length) {
            scope.selectResult(scope.results[scope.currentIndex]);
            scope.$apply();
            event.preventDefault();
          } else {
            event.preventDefault();
            if (scope.overrideSuggestions) {
              setInputString(scope.searchStr);
              scope.$apply();
            }
            else {
              scope.results = [];
              scope.$apply();
            }
          }

        } else if (event.which === KEY_ES) {
          scope.results = [];
          scope.showDropdown = false;
          scope.$apply();
        } else if (event.which === KEY_BS || event.which === KEY_DEL) {
          scope.selectedObject = null;
          scope.$apply();
        }
      });
    }
  };
}]);

<|endoftext|>


<commit_before>module.exports = {
  up: function (migration, DataTypes) {
    return migration.createTable('Bikes', {
      id: {
        primaryKey: true,
        allowNull: false,
        type: DataTypes.UUID
      },
      name: {
        allowNull: false,
        type: DataTypes.STRING
      },
      size: {
        allowNull: false,
        type: DataTypes.INTEGER
      },
      type: {
        allowNull: false,
        type: DataTypes.ENUM([
          'image/png',
          'image/jpeg'
        ])
      },
      createdAt: {
        allowNull: false,
        type: DataTypes.DATE
      },
      updatedAt: {
        allowNull: false,
        type: DataTypes.DATE
      },
      BikeshedId: {
        allowNull: false,
        type: DataTypes.UUID
      }
    })
  },
  down: function (migration) {
    return migration.dropTable('Bikes')
  }
}
<commit_msg>Add width and height to bike model<commit_after>module.exports = {
  up: function (migration, DataTypes) {
    return migration.createTable('Bikes', {
      id: {
        primaryKey: true,
        allowNull: false,
        type: DataTypes.UUID
      },
      name: {
        allowNull: false,
        type: DataTypes.STRING
      },
      size: {
        allowNull: false,
        type: DataTypes.INTEGER
      },
      width: {
        allowNull: false,
        type: DataTypes.INTEGER
      },
      height: {
        allowNull: false,
        type: DataTypes.INTEGER
      },
      type: {
        allowNull: false,
        type: DataTypes.ENUM([
          'image/png',
          'image/jpeg'
        ])
      },
      createdAt: {
        allowNull: false,
        type: DataTypes.DATE
      },
      updatedAt: {
        allowNull: false,
        type: DataTypes.DATE
      },
      BikeshedId: {
        allowNull: false,
        type: DataTypes.UUID
      }
    })
  },
  down: function (migration) {
    return migration.dropTable('Bikes')
  }
}
<|endoftext|>


<commit_before>import { getEventKey, stopAndPrevent } from '../utils/event'
import { normalizeToInterval } from '../utils/format'

export default {
  data: () => ({
    keyboardIndex: 0,
    keyboardMoveDirection: false,
    keyboardMoveTimer: false
  }),
  methods: {
    __keyboardShow (index = 0) {
      if (this.keyboardIndex !== index) {
        this.keyboardIndex = index
      }
    },
    __keyboardSetCurrentSelection () {
      if (this.keyboardIndex >= 0 && this.keyboardIndex <= this.keyboardMaxIndex) {
        this.__keyboardSetSelection(this.keyboardIndex)
      }
    },
    __keyboardHandleKey (e) {
      const key = getEventKey(e)

      switch (key) {
        case 38: // UP key
          this.__keyboardMoveCursor(-1, e)
          break
        case 40: // DOWN key
          this.__keyboardMoveCursor(1, e)
          break
        case 13: // ENTER key
        case 32: // SPACE key
          if (this.$refs.popover.showing) {
            stopAndPrevent(e)
            this.__keyboardSetCurrentSelection()
            return
          }
          break
        case 9: // TAB key
          this.hide()
          break
      }

      this.__keyboardCustomKeyHandle(key, e)
    },
    __keyboardMoveCursor (offset, e) {
      stopAndPrevent(e)

      if (this.$refs.popover.showing) {
        clearTimeout(this.keyboardMoveTimer)
        let
          index = this.keyboardIndex,
          valid = this.__keyboardIsSelectableIndex || (() => true)

        do {
          index = normalizeToInterval(
            index + offset,
            0,
            this.keyboardMaxIndex
          )
        }
        while (index !== this.keyboardIndex && !valid(index))

        this.keyboardMoveDirection = index > this.keyboardIndex ? 1 : -1
        this.keyboardMoveTimer = setTimeout(() => { this.keyboardMoveDirection = false }, 500)
        this.keyboardIndex = index
        return
      }

      this.__keyboardShowTrigger()
    }
  }
}
<commit_msg>fix: QAutocomplete - when Popover is showing you can't type space character #1652<commit_after>import { getEventKey, stopAndPrevent } from '../utils/event'
import { normalizeToInterval } from '../utils/format'

export default {
  data: () => ({
    keyboardIndex: 0,
    keyboardMoveDirection: false,
    keyboardMoveTimer: false
  }),
  methods: {
    __keyboardShow (index = 0) {
      if (this.keyboardIndex !== index) {
        this.keyboardIndex = index
      }
    },
    __keyboardSetCurrentSelection () {
      if (this.keyboardIndex >= 0 && this.keyboardIndex <= this.keyboardMaxIndex) {
        this.__keyboardSetSelection(this.keyboardIndex)
      }
    },
    __keyboardHandleKey (e) {
      const key = getEventKey(e)

      switch (key) {
        case 38: // UP key
          this.__keyboardMoveCursor(-1, e)
          break
        case 40: // DOWN key
          this.__keyboardMoveCursor(1, e)
          break
        case 13: // ENTER key
        case 32: // SPACE key
          if (this.$refs.popover.showing && !this.inputEl) {
            stopAndPrevent(e)
            this.__keyboardSetCurrentSelection()
            return
          }
          break
        case 9: // TAB key
          this.hide()
          break
      }

      this.__keyboardCustomKeyHandle(key, e)
    },
    __keyboardMoveCursor (offset, e) {
      stopAndPrevent(e)

      if (this.$refs.popover.showing) {
        clearTimeout(this.keyboardMoveTimer)
        let
          index = this.keyboardIndex,
          valid = this.__keyboardIsSelectableIndex || (() => true)

        do {
          index = normalizeToInterval(
            index + offset,
            0,
            this.keyboardMaxIndex
          )
        }
        while (index !== this.keyboardIndex && !valid(index))

        this.keyboardMoveDirection = index > this.keyboardIndex ? 1 : -1
        this.keyboardMoveTimer = setTimeout(() => { this.keyboardMoveDirection = false }, 500)
        this.keyboardIndex = index
        return
      }

      this.__keyboardShowTrigger()
    }
  }
}
<|endoftext|>


<commit_before>importScripts('/workbox-sw.prod.v2.0.1js');
importScripts('/workbox-runtime-caching.prod.v2.0.0.js');

const workboxSW = new WorkboxSW({ clientsClaim: true });

workboxSW.precache([]);

workboxSW.router.registerRoute(
  '/',
  workboxSW.strategies.networkFirst()
);

workboxSW.router.registerRoute(
  '/posts/(.*)',
  workboxSW.strategies.networkFirst()
);

workboxSW.router.registerRoute(
  '/api/(.*)',
  workboxSW.strategies.networkFirst()
);

workboxSW.router.registerRoute(
  '/about',
  workboxSW.strategies.cacheFirst()
);

workboxSW.router.registerRoute(
  'https://fonts.googleapis.com/(.*)',
  workboxSW.strategies.cacheFirst({
    cacheableResponse: { statuses: [0, 200] }
  })
);

workboxSW.router.registerRoute(
  'https://fonts.gstatic.com/(.*)',
  workboxSW.strategies.cacheFirst({
    cacheableResponse: { statuses: [0, 200] }
  })
);

const custom = new workbox.runtimeCaching.RequestWrapper();

self.addEventListener('message', function(event) {
  if (event.data && event.data.action === 'navigate') {
    custom.fetchAndCache({ request: new Request(event.data.url) });
  }
});<commit_msg>Update workbox<commit_after>importScripts('/workbox-sw.prod.v2.0.1.js');
importScripts('/workbox-runtime-caching.prod.v2.0.0.js');

const workboxSW = new WorkboxSW({ clientsClaim: true });

workboxSW.precache([]);

workboxSW.router.registerRoute(
  '/',
  workboxSW.strategies.networkFirst()
);

workboxSW.router.registerRoute(
  '/posts/(.*)',
  workboxSW.strategies.networkFirst()
);

workboxSW.router.registerRoute(
  '/api/(.*)',
  workboxSW.strategies.networkFirst()
);

workboxSW.router.registerRoute(
  '/about',
  workboxSW.strategies.cacheFirst()
);

workboxSW.router.registerRoute(
  'https://fonts.googleapis.com/(.*)',
  workboxSW.strategies.cacheFirst({
    cacheableResponse: { statuses: [0, 200] }
  })
);

workboxSW.router.registerRoute(
  'https://fonts.gstatic.com/(.*)',
  workboxSW.strategies.cacheFirst({
    cacheableResponse: { statuses: [0, 200] }
  })
);

const custom = new workbox.runtimeCaching.RequestWrapper();

self.addEventListener('message', function(event) {
  if (event.data && event.data.action === 'navigate') {
    custom.fetchAndCache({ request: new Request(event.data.url) });
  }
});<|endoftext|>


<commit_before>jQuery(function($) {
    var viewport = $("#viewport");
    var canvas = $("#canvas");
    var edited_note = null;
    var dragNoteDOM = null;
    var dragNote = null;
    var dragLastX = 0;
    var dragLastY = 0;

    function onCreateNoteSuccess(id, note) {
        window.notepage.children.push(note);
        drawNote(note);
    }

    function onUpdateNotepageSuccess(id, result_block) {
        var notepage_revision_id = result_block['notepage_revision_id'];
        var results = result_block['results'];
        var i, result, note, pos_um, size_um, z_index, contents_markdown;

        window.notepage.revision_id = notepage_revision_id;

        for (i = 0; i < results.length; ++i) {
            result = results[i];
            note = getNoteById(result['note_id']);
            if (note === null) {
                console.log("onUpdateNotepageSuccess: cannot find note id " +
                            result['note_id']);
                continue;
            }

            pos_um = result['pos_um'];
            size_um = result['size_um'];
            z_index = result['z_index'];
            contents_markdown = result['contents_markdown'];

            if (pos_um !== undefined && pos_um !== null) {
                note.pos_um = pos_um;
            }

            if (size_um !== undefined && size_um !== null) {
                note.size_um = size_um;
            }

            if (z_index !== undefined && z_index !== null) {
                note.z_index = z_index;
            }

            if (contents_markdown !== undefined && contents_markdown !== null) {
                note.contents_markdown = contents_markdown;
            }

            drawNote(note);
        }

        return;
    }

    function onUpdateNotepageError(id) {
        console.log("Failed update");
    }

    function drawNote(note) {
        var domId, noteDOM, noteContentsDOM, style, converter;

        domId = "note-" + note.node_id;
        noteDOM = $("#" + domId);

        if (noteDOM.length == 0) {
            // New note; need to create it.
            $('
' +
              '

' +
              '
').appendTo(canvas);
            noteDOM = $("#" + domId);
            noteDOM.data("note", note);
            noteContentsDOM = $(".note-contents", noteDOM);

            style = {'width': (0.001 * note.size_um[0]) + "mm",
                     'height': (0.001 * note.size_um[1]) + "mm",
                     'left': (0.001 * note.pos_um[0]) + "mm",
                     'top': (0.001 * note.pos_um[1]) + "mm",
                     'z-index': note.z_index}

            noteDOM.css(style);
            noteDOM.mousedown(onNoteMouseDown);
            noteDOM.dblclick(onNoteDoubleClick);
            noteContentsDOM.mousedown(onNoteMouseDown);
        } else {
            noteContentsDOM = $(".note-contents", noteDOM);
        }

        // Convert the raw text into HTML.
        converter = Markdown.getSanitizingConverter();
        noteContentsDOM.html(
            converter.makeHtml(note.contents_markdown));

        // Make sure the contents are visible.
        noteContentsDOM.css("display", "block");
    }

    function updateNote(note, text) {
        dozer.update_notepage(
            window.notepage.node_id,
            [{"action": "edit_note",
              "note_id": note.node_id,
              "revision_id": note.revision_id,
              "contents_markdown": text}],
            onUpdateNotepageSuccess,
            onUpdateNotepageError);
    }

    function stopDragging() {
        var note = dragNote;
        var pos_um;

        // Stop any drag operation currently in progress.
        if (! dragNoteDOM) {
            // Nothing being dragged.
            return false;
        }

        pos_um = getNotePositionInMicrons(dragNoteDOM);

        // Stop the drag action
        dragNoteDOM = null;
        dragNote = null;

        if (pos_um[0] === note.pos_um[0] && pos_um[1] === note.pos_um[1]) {
            // The note didn't move; don't fire an update event.
            return false;
        }

        // Update the server with the new note position.
        dozer.update_notepage(
            window.notepage.node_id,
            [{"action": "edit_note",
              "note_id": note.node_id,
              "revision_id": note.revision_id,
              "pos_um": pos_um}],
            onUpdateNotepageSuccess,
            onUpdateNotepageError);

        return false;
    }

    function onNoteMouseDown(e) {
        // Handle a mousedown event on a note.  This starts dragging the note.
        var noteDOM = $(e.target);

        if (! noteDOM.is(".note")) {
            // Mouse down on an inner item; select the note div.
            noteDOM = noteDOM.parents(".note");
        }

        if (e.button === 0 && e.target === e.currentTarget) {
            // Left button being pressed on the note itself.
            dragNoteDOM = noteDOM;
            dragNote = noteDOM.data("note");
            dragLastX = e.clientX;
            dragLastY = e.clientY;

            // Don't let this event bubble.
            return false;
        }
    }

    function onMouseMove(e) {
        // Handle a mouse motion event on the canvas.  If a drag event is in
        // progress, this updates the position of the note on the canvas.
        var deltaX, deltaY, left, top;

        if (dragNoteDOM) {
            // A note is being moved.

            if (e.which !== 1) {
                // Mouse button was released, but we didn't receive the
                // mouseup event.  Go ahead and release the drag now.
                stopDragging();
                return;
            }

            // Delta is the difference between the current position in the
            // client window and the last reported position.
            deltaX = e.clientX - dragLastX;
            deltaY = e.clientY - dragLastY;

            // Get the position of the target.  We use the truncating
            // "feature" of parseInt to get rid of the "px" suffix and
            // convert the string to an integer.
            left = parseInt(dragNoteDOM.css('left'));
            top = parseInt(dragNoteDOM.css('top'));

            // Modify the position by the delta.
            left += deltaX;
            top += deltaY;

            dragNoteDOM.css("left", left);
            dragNoteDOM.css("top", top);

            // Remember the last reported position.
            dragLastX = e.clientX;
            dragLastY = e.clientY;
        }
    }

    function onNoteDoubleClick(e) {
        // Handle a double-click event on a note.  This starts editing the
        // note.
        var noteDOM = $(e.target), form, editor;

        if (! noteDOM.is(".note")) {
            // Clicked on the contents div; set noteDOM to the enclosing
            // note div.
            noteDOM = noteDOM.parents(".note");
        }

        edited_note = noteDOM.data("note");

        // Remove the display-only contents while editing.
        $(".note-contents", noteDOM).css("display", "none");

        // Create an edit form in the interior.
        form = $('<form><textarea id="note-edit" cols="132" rows="60">' +
                 '</textarea></form>');
        form.appendTo(noteDOM);
        editor = $("#note-edit", form);

        // Populate the value of the note with the contents.
        editor.text(edited_note.contents_markdown);

        // Watch keypresses for Alt+Enter or Escape, which terminate the
        // editing process.
        editor.keydown(onNoteEditKeyDown);
        editor.trigger("focus");

        // Don't let this event bubble.
        return false;
    }

    function onNoteEditKeyDown(e) {
        var target = $(e.target);
        var text;

        if (e.which === 27) {
            // Escape -- cancel editing.
            target.parent().remove();
            drawNote(edited_note);
            edited_note = null;
            return false;
        }

        if ((e.altKey || e.metaKey) && (e.which === 10 || e.which === 13)) {
            // Alt+Enter pressed -- save changes.

            // Get the text entered.
            text = target.val();

            // Remove the form.
            target.parent().remove();

            // Update the note.
            updateNote(edited_note, text);

            edited_note = false;
            return false;
        }

        // Normal key; ignore it, let it bubble up.
        return true;
    }

    function getPixelsPerMicron() {
        var sizetest = $('

');
        var width, height;

        // Create a dummy div that's 100mm x 100mm and see how many pixels
        // that takes up.  Using a div that's too small results in significant
        // rounding errors.

        sizetest.appendTo("#viewport")
        sizetest = $("#sizetest");
        width = parseInt(sizetest.css("width"));
        height = parseInt(sizetest.css("height"));

        // Remove our dummy div.
        sizetest.remove();

        // We need to scale by 1e-5 to go from hundreds of mm to microns.
        return [1e-5 * width, 1e-5 * height];
    }

    function getNoteById(note_id) {
        var i, note;

        for (i = 0; i < window.notepage.children.length; ++i) {
            note = window.notepage.children[i];
            if (note.node_id == note_id) {
                return note;
            }
        }

        return null;
    }

    function getNoteSizeInMicrons(noteDOM, pixelsPerMicron) {
        var width = parseInt(noteDOM.css("width"));
        var height = parseInt(noteDOM.css("height"));

        if (pixelsPerMicron === undefined || pixelsPerMicron === null) {
            pixelsPerMicron = getPixelsPerMicron();
        }

        width = Math.round(width / pixelsPerMicron[0]);
        height = Math.round(height / pixelsPerMicron[1]);

        return [width, height];
    }

    function getNotePositionInMicrons(noteDOM, pixelsPerMicron) {
        var left = noteDOM.css("left");
        var top = noteDOM.css("top");

        if (left === undefined || top === undefined) {
            console.log("Failed to retrieve style information");
            return;
        }

        if (pixelsPerMicron === undefined || pixelsPerMicron === null) {
            pixelsPerMicron = getPixelsPerMicron();
        }

        left = Math.round(parseInt(left) / pixelsPerMicron[0]);
        top = Math.round(parseInt(top) / pixelsPerMicron[1]);

        return [left, top];
    }

    // Resize the viewport so its height is the height of the document.
    viewport.height(window.innerHeight - viewport.offset().top - 20);

    // Bind the "Create note" link.
    $("#createNoteAction").click(function () {
        dozer.create_note(window.notepage.node_id, onCreateNoteSuccess, null);
    });

    // Bind motion events to allow dragging of notes.
    $(window).mousemove(onMouseMove);
    $(window).mouseup(stopDragging);
    $(window).on("blur", stopDragging);

    // Add each note to the document.
    (function () {
        for (var i = 0; i < window.notepage.children.length; ++i) {
            var note = window.notepage.children[i];
            drawNote(note);
        }
    })();
});
<commit_msg>Move drag APIs into their own namespace.<commit_after>jQuery(function($) {
    var viewport = $("#viewport");
    var canvas = $("#canvas");
    var edited_note = null;
    var drag;

    function getPixelsPerMicron() {
        var sizetest = $('

');
        var width, height;

        // Create a dummy div that's 100mm x 100mm and see how many pixels
        // that takes up.  Using a div that's too small results in significant
        // rounding errors.

        sizetest.appendTo("#viewport")
        sizetest = $("#sizetest");
        width = parseInt(sizetest.css("width"));
        height = parseInt(sizetest.css("height"));

        // Remove our dummy div.
        sizetest.remove();

        // We need to scale by 1e-5 to go from hundreds of mm to microns.
        return [1e-5 * width, 1e-5 * height];
    }

    function getNoteById(note_id) {
        var i, note;

        for (i = 0; i < window.notepage.children.length; ++i) {
            note = window.notepage.children[i];
            if (note.node_id == note_id) {
                return note;
            }
        }

        return null;
    }

    function getNoteSizeInMicrons(noteDOM, pixelsPerMicron) {
        var width = parseInt(noteDOM.css("width"));
        var height = parseInt(noteDOM.css("height"));

        if (pixelsPerMicron === undefined || pixelsPerMicron === null) {
            pixelsPerMicron = getPixelsPerMicron();
        }

        width = Math.round(width / pixelsPerMicron[0]);
        height = Math.round(height / pixelsPerMicron[1]);

        return [width, height];
    }

    function getNotePositionInMicrons(noteDOM, pixelsPerMicron) {
        var left = noteDOM.css("left");
        var top = noteDOM.css("top");

        if (left === undefined || top === undefined) {
            console.log("Failed to retrieve style information");
            return;
        }

        if (pixelsPerMicron === undefined || pixelsPerMicron === null) {
            pixelsPerMicron = getPixelsPerMicron();
        }

        left = Math.round(parseInt(left) / pixelsPerMicron[0]);
        top = Math.round(parseInt(top) / pixelsPerMicron[1]);

        return [left, top];
    }

    function drawNote(note) {
        var domId, noteDOM, noteContentsDOM, style, converter;

        domId = "note-" + note.node_id;
        noteDOM = $("#" + domId);

        if (noteDOM.length == 0) {
            // New note; need to create it.
            $('
' +
              '

' +
              '
').appendTo(canvas);
            noteDOM = $("#" + domId);
            noteDOM.data("note", note);
            noteContentsDOM = $(".note-contents", noteDOM);

            style = {'width': (0.001 * note.size_um[0]) + "mm",
                     'height': (0.001 * note.size_um[1]) + "mm",
                     'left': (0.001 * note.pos_um[0]) + "mm",
                     'top': (0.001 * note.pos_um[1]) + "mm",
                     'z-index': note.z_index}

            noteDOM.css(style);
            noteDOM.mousedown(onNoteMouseDown);
            noteDOM.dblclick(onNoteDoubleClick);
            noteContentsDOM.mousedown(onNoteMouseDown);
        } else {
            noteContentsDOM = $(".note-contents", noteDOM);
        }

        // Convert the raw text into HTML.
        converter = Markdown.getSanitizingConverter();
        noteContentsDOM.html(
            converter.makeHtml(note.contents_markdown));

        // Make sure the contents are visible.
        noteContentsDOM.css("display", "block");
    }

    function updateNote(note, text) {
        dozer.update_notepage(
            window.notepage.node_id,
            [{"action": "edit_note",
              "note_id": note.node_id,
              "revision_id": note.revision_id,
              "contents_markdown": text}],
            onUpdateNotepageSuccess,
            onUpdateNotepageError);
    }

    drag = (function () {
        var dragNoteDOM = null;
        var dragNote = null;
        var dragLastX = 0;
        var dragLastY = 0;
        var start, stop, move;

        stop = function () {
            var note = dragNote;
            var pos_um;

            // Stop any drag operation currently in progress.
            if (! dragNoteDOM) {
                // Nothing being dragged.
                return false;
            }

            pos_um = getNotePositionInMicrons(dragNoteDOM);

            // Stop the drag action
            dragNoteDOM = null;
            dragNote = null;

            if (pos_um[0] === note.pos_um[0] &&
                pos_um[1] === note.pos_um[1]) {
                // The note didn't move; don't fire an update event.
                return false;
            }

            // Update the server with the new note position.
            dozer.update_notepage(
                window.notepage.node_id,
                [{"action": "edit_note",
                  "note_id": note.node_id,
                  "revision_id": note.revision_id,
                  "pos_um": pos_um}],
                onUpdateNotepageSuccess,
                onUpdateNotepageError);

            return false;
        };

        start = function (e) {
            // Find the note being dragged.
            dragNoteDOM = $(e.target);

            if (! dragNoteDOM.is(".note")) {
                // The button was pressed on an element within the note.
                dragNoteDOM = dragNoteDOM.parents(".note");
            }

            dragNote = dragNoteDOM.data("note");
            dragLastX = e.clientX;
            dragLastY = e.clientY;
            return false;
        };

        move = function (e) {
            var deltaX, deltaY, left, top;

            if (! dragNoteDOM) {
                // Nothing is being dragged.
                return false;
            }

            if (e.which !== 1) {
                // Mouse button was released; stop dragging.
                return stop(e);
            }

            // Delta is the difference between the current position in the
            // client window and the last reported position.
            deltaX = e.clientX - dragLastX;
            deltaY = e.clientY - dragLastY;

            // Get the position of the target.  We use the truncating
            // "feature" of parseInt to get rid of the "px" suffix and
            // convert the string to an integer.
            left = parseInt(dragNoteDOM.css('left'));
            top = parseInt(dragNoteDOM.css('top'));

            // Modify the position by the delta.
            left += deltaX;
            top += deltaY;

            dragNoteDOM.css("left", left);
            dragNoteDOM.css("top", top);

            // Remember the last reported position.
            dragLastX = e.clientX;
            dragLastY = e.clientY;
        };

        return {'start': start, 'stop': stop, 'move': move};
    })();

    function onCreateNoteSuccess(id, note) {
        notepage.children.push(note);
        drawNote(note);
    }

    function onUpdateNotepageSuccess(id, result_block) {
        var notepage_revision_id = result_block['notepage_revision_id'];
        var results = result_block['results'];
        var i, result, note, pos_um, size_um, z_index, contents_markdown;

        window.notepage.revision_id = notepage_revision_id;

        for (i = 0; i < results.length; ++i) {
            result = results[i];
            note = getNoteById(result['note_id']);
            if (note === null) {
                console.log("onUpdateNotepageSuccess: cannot find note id " +
                            result['note_id']);
                continue;
            }

            pos_um = result['pos_um'];
            size_um = result['size_um'];
            z_index = result['z_index'];
            contents_markdown = result['contents_markdown'];

            if (pos_um !== undefined && pos_um !== null) {
                note.pos_um = pos_um;
            }

            if (size_um !== undefined && size_um !== null) {
                note.size_um = size_um;
            }

            if (z_index !== undefined && z_index !== null) {
                note.z_index = z_index;
            }

            if (contents_markdown !== undefined && contents_markdown !== null) {
                note.contents_markdown = contents_markdown;
            }

            drawNote(note);
        }

        return;
    }

    function onUpdateNotepageError(id) {
        console.log("Failed update");
    }

    function onNoteMouseDown(e) {
        if (e.button === 0 && e.target === e.currentTarget) {
            // Left button being pressed on the note itself.
            return drag.start(e);
        }
    }

    function onWindowMouseMove(e) {
        // Handle mouse motion events.  If a drag event is in progress, this
        // updates the position of the note on the canvas.
        return drag.move(e);
    }

    function onWindowMouseUp(e) {
        // If a drag event is in progress, stop it.
        return drag.stop(e);
    }

    function onWindowBlur(e) {
        // If a drag event is in progress, stop it.
        return drag.stop(e);
    }

    function onNoteDoubleClick(e) {
        // Handle a double-click event on a note.  This starts editing the
        // note.
        var noteDOM = $(e.target), form, editor;

        if (! noteDOM.is(".note")) {
            // Clicked on the contents div; set noteDOM to the enclosing
            // note div.
            noteDOM = noteDOM.parents(".note");
        }

        edited_note = noteDOM.data("note");

        // Remove the display-only contents while editing.
        $(".note-contents", noteDOM).css("display", "none");

        // Create an edit form in the interior.
        form = $('<form><textarea id="note-edit" cols="132" rows="60">' +
                 '</textarea></form>');
        form.appendTo(noteDOM);
        editor = $("#note-edit", form);

        // Populate the value of the note with the contents.
        editor.text(edited_note.contents_markdown);

        // Watch keypresses for Alt+Enter or Escape, which terminate the
        // editing process.
        editor.keydown(onNoteEditKeyDown);
        editor.trigger("focus");

        // Don't let this event bubble.
        return false;
    }

    function onNoteEditKeyDown(e) {
        var target = $(e.target);
        var text;

        if (e.which === 27) {
            // Escape -- cancel editing.
            target.parent().remove();
            drawNote(edited_note);
            edited_note = null;
            return false;
        }

        if ((e.altKey || e.metaKey) && (e.which === 10 || e.which === 13)) {
            // Alt+Enter pressed -- save changes.

            // Get the text entered.
            text = target.val();

            // Remove the form.
            target.parent().remove();

            // Update the note.
            updateNote(edited_note, text);

            edited_note = false;
            return false;
        }

        // Normal key; ignore it, let it bubble up.
        return true;
    }
    // Resize the viewport so its height is the height of the document.
    viewport.height(window.innerHeight - viewport.offset().top - 20);

    // Bind the "Create note" link.
    $("#createNoteAction").click(function () {
        dozer.create_note(window.notepage.node_id, onCreateNoteSuccess, null);
    });

    // Bind motion events to allow dragging of notes.
    $(window).mousemove(onWindowMouseMove);
    $(window).mouseup(onWindowMouseUp);
    $(window).on("blur", onWindowBlur);

    // Add each note to the document.
    (function () {
        for (var i = 0; i < window.notepage.children.length; ++i) {
            var note = window.notepage.children[i];
            drawNote(note);
        }
    })();
});
<|endoftext|>


<commit_before>const fs = require("fs");
const awaitable = require("@scriptabuild/awaitable");

function load(filename) {
    return {
        async json() {
            try {
                let rawdata = await awaitable(cb => fs.readFile(filename, cb));
                let data = JSON.parse(rawdata);
                return data;
            }
            catch (err) {
                return undefined;
            }
        }
        // text
        // stream buffer
    };
}

function folder(path) {
    // write to next file in folder
    // append to last file in folder
    // read last file in folder
    // create next folder

    return {
        async ensure() {
            let lix = 0;
            while (lix != -1) {
                try {
                    lix = path.indexOf("/", lix + 1);
                    let newFolder = lix === -1 ? path : path.substring(0, lix);
                    await awaitable(cb => fs.mkdir(newFolder, 0o777, cb));
                }
                catch (err) {
                    console.log("---", err);
                }

            }
        }
    }
}

function save(filename) {
    return {
        async json(data) {
            try {
                let jsondata = JSON.stringify(data);
                await awaitable(cb => fs.writeFile(filename, jsondata, { mode: "w" }, cb));
            }
            catch (err) {
                return undefined;
            }
        }
        // text
        // stream buffer
    };
}

module.exports = {
    load,
    save,
    folder
};<commit_msg>First implementation of .ensure() that "kinda works" with windows.<commit_after>const fs = require("fs");
const awaitable = require("@scriptabuild/awaitable");

function load(filename) {
    return {
        async json() {
            try {
                let rawdata = await awaitable(cb => fs.readFile(filename, cb));
                let data = JSON.parse(rawdata);
                return data;
            }
            catch (err) {
                return undefined;
            }
        }
        // text
        // stream buffer
    };
}

function folder(path) {
    // write to next file in folder
    // append to last file in folder
    // read last file in folder
    // create next folder

    return {
        async ensure() {
            if (/^win/.test(process.platform)) {
                try {
                    await awaitable(cb => fs.mkdir(path, 0o777, cb));
                    return;
                }
                catch (err) {
                    throw new Error(".ensure() will not recursivly create missing folders on Windows yet. Please submit a pull request if you fix this!");
	                //NOTE: On Windows, a file path will not start with /, but instead a drive letter or a UNC path. (Ie. C:, C:\ or \\)
				}
            }

            let lix = 0;
            while (lix != -1) {
                try {
                    lix = path.indexOf("/", lix + 1);
                    let newFolder = lix === -1 ? path : path.substring(0, lix);
                    await awaitable(cb => fs.mkdir(newFolder, 0o777, cb));
                }
                catch (err) {
                    console.log("---", err);
                }

            }
        }
    }
}

function save(filename) {
    return {
        async json(data) {
            try {
                let jsondata = JSON.stringify(data);
                await awaitable(cb => fs.writeFile(filename, jsondata, { mode: "w" }, cb));
            }
            catch (err) {
                return undefined;
            }
        }
        // text
        // stream buffer
    };
}

module.exports = {
    load,
    save,
    folder
};<|endoftext|>


<commit_before>if (self.importScripts) {
  importScripts('../resources/fetch-test-helpers.js');
}

async_test(function(t) {
    fetch('http://')
      .then(
        t.unreached_func('fetch of invalid URL must fail'),
        function(e) {
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch invalid URL');

// https://fetch.spec.whatwg.org/#fetching
// Step 4:
// request's url's scheme is not one of "http" and "https"
//   A network error.
async_test(function(t) {
    fetch('ftp://localhost/')
      .then(
        t.unreached_func('fetch of non-HTTP(S) CORS must fail'),
        function(e) {
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'fetch non-HTTP(S) CORS');

async_test(function(t) {
    fetch('/serviceworker/resources/fetch-status.php?status=200')
      .then(function(response) {
          assert_equals(response.status, 200);
          assert_equals(response.statusText, 'OK');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch result of 200 response');

async_test(function(t) {
    fetch('/serviceworker/resources/fetch-status.php?status=404')
      .then(function(response) {
          assert_equals(response.status, 404);
          assert_equals(response.statusText, 'Not Found');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch result of 404 response');

async_test(function(t) {
    var request = new Request(
      '/serviceworker/resources/fetch-status.php?status=200#fragment');

    // The url attribute's getter must return request's url,
    // serialized with the exclude fragment flag set.
    assert_equals(request.url,
      'http://127.0.0.1:8000/serviceworker/resources/fetch-status.php' +
      '?status=200');

    fetch(request)
      .then(function(response) {
          assert_equals(response.status, 200);
          assert_equals(response.statusText, 'OK');
          // The url attribute's getter must return the empty string
          // if response's url is null and response's url,
          // serialized with the exclude fragment flag set, otherwise.
          assert_equals(response.url,
            'http://127.0.0.1:8000/serviceworker/resources/fetch-status.php' +
            '?status=200');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Request/response url attribute getter with fragment');

function evalJsonp(text) {
  return new Promise(function(resolve) {
      var report = resolve;
      // text must contain report() call.
      eval(text);
    });
}

async_test(function(t) {
    var request =
      new Request('/serviceworker/resources/fetch-access-control.php',
                  {
                    method: 'POST',
                    body: new Blob(['Test Blob'], {type: 'test/type'})
                  });
    fetch(request)
      .then(function(response) { return response.text(); })
      .then(evalJsonp)
      .then(function(result) {
          assert_equals(result.method, 'POST');
          assert_equals(result.body, 'Test Blob');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch with Blob body test');

async_test(function(t) {
    var request = new Request(
      '/serviceworker/resources/fetch-access-control.php',
      {method: 'POST', body: 'Test String'});
    fetch(request)
      .then(function(response) { return response.text(); })
      .then(evalJsonp)
      .then(function(result) {
          assert_equals(result.method, 'POST');
          assert_equals(result.body, 'Test String');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch with string body test');

async_test(function(t) {
    var text = 'Test ArrayBuffer';
    var array = new Uint8Array(text.length);
    for (var i = 0; i < text.length; ++i)
      array[i] = text.charCodeAt(i);
    var request = new Request(
      '/serviceworker/resources/fetch-access-control.php',
      {method: 'POST', body: array.buffer});
    fetch(request)
      .then(function(response) { return response.text(); })
      .then(evalJsonp)
      .then(function(result) {
          assert_equals(result.method, 'POST');
          assert_equals(result.body, 'Test ArrayBuffer');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch with ArrayBuffer body test');

async_test(function(t) {
    var text = 'Test ArrayBufferView';
    var array = new Uint8Array(text.length);
    for (var i = 0; i < text.length; ++i)
      array[i] = text.charCodeAt(i);
    var request = new Request(
      '/serviceworker/resources/fetch-access-control.php',
      {method: 'POST', body: array});
    fetch(request)
      .then(function(response) { return response.text(); })
      .then(evalJsonp)
      .then(function(result) {
          assert_equals(result.method, 'POST');
          assert_equals(result.body, 'Test ArrayBufferView');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch with ArrayBufferView body test');

async_test(function(t) {
    var formData = new FormData();
    formData.append('StringKey1', '1234567890');
    formData.append('StringKey2', 'ABCDEFGHIJ');
    formData.append('BlobKey', new Blob(['blob content']));
    formData.append('FileKey',
                    new File(['file content'], 'file.dat'));
    var request = new Request(
      '/serviceworker/resources/fetch-access-control.php',
      {method: 'POST', body: formData});
    fetch(request)
      .then(function(response) { return response.text(); })
      .then(evalJsonp)
      .then(function(result) {
          assert_equals(result.method, 'POST');
          assert_equals(result.post['StringKey1'], '1234567890');
          assert_equals(result.post['StringKey2'], 'ABCDEFGHIJ');
          var files = [];
          for (var i = 0; i < result.files.length; ++i) {
            files[result.files[i].key] = result.files[i];
          }
          assert_equals(files['BlobKey'].content, 'blob content');
          assert_equals(files['BlobKey'].name, 'blob');
          assert_equals(files['BlobKey'].size, 12);
          assert_equals(files['FileKey'].content, 'file content');
          assert_equals(files['FileKey'].name, 'file.dat');
          assert_equals(files['FileKey'].size, 12);
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch with FormData body test');

test(function(t) {
    function runInfiniteFetchLoop() {
      fetch('dummy.html')
        .then(function() { runInfiniteFetchLoop(); });
    }
    runInfiniteFetchLoop();
  },
  'Destroying the execution context while fetch is happening should not ' +
  'cause a crash.');

done();
<commit_msg>[Fetch] Add a layout test for Request/Response URL with redirect<commit_after>if (self.importScripts) {
  importScripts('../resources/fetch-test-helpers.js');
}

async_test(function(t) {
    fetch('http://')
      .then(
        t.unreached_func('fetch of invalid URL must fail'),
        function(e) {
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch invalid URL');

// https://fetch.spec.whatwg.org/#fetching
// Step 4:
// request's url's scheme is not one of "http" and "https"
//   A network error.
async_test(function(t) {
    fetch('ftp://localhost/')
      .then(
        t.unreached_func('fetch of non-HTTP(S) CORS must fail'),
        function(e) {
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'fetch non-HTTP(S) CORS');

async_test(function(t) {
    fetch('/serviceworker/resources/fetch-status.php?status=200')
      .then(function(response) {
          assert_equals(response.status, 200);
          assert_equals(response.statusText, 'OK');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch result of 200 response');

async_test(function(t) {
    fetch('/serviceworker/resources/fetch-status.php?status=404')
      .then(function(response) {
          assert_equals(response.status, 404);
          assert_equals(response.statusText, 'Not Found');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch result of 404 response');

async_test(function(t) {
    var request = new Request(
      '/serviceworker/resources/fetch-status.php?status=200#fragment');

    // The url attribute's getter must return request's url,
    // serialized with the exclude fragment flag set.
    assert_equals(request.url,
      'http://127.0.0.1:8000/serviceworker/resources/fetch-status.php' +
      '?status=200');

    fetch(request)
      .then(function(response) {
          assert_equals(response.status, 200);
          assert_equals(response.statusText, 'OK');
          // The url attribute's getter must return the empty string
          // if response's url is null and response's url,
          // serialized with the exclude fragment flag set, otherwise.
          assert_equals(response.url,
            'http://127.0.0.1:8000/serviceworker/resources/fetch-status.php' +
            '?status=200');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Request/response url attribute getter with fragment');

async_test(function(t) {
    var redirect_target_url =
      'http://127.0.0.1:8000/serviceworker/resources/fetch-status.php' +
      '?status=200';
    var redirect_original_url =
      'http://127.0.0.1:8000/serviceworker/resources/redirect.php?Redirect=' +
      redirect_target_url;

    var request = new Request(redirect_original_url);
    assert_equals(request.url, redirect_original_url,
      'Request\'s url is the original URL');

    fetch(request)
      .then(function(response) {
          assert_equals(response.status, 200);
          assert_equals(response.statusText, 'OK');
          assert_equals(response.url, redirect_target_url,
            'Response\'s url is locationURL');
          assert_equals(request.url, redirect_original_url,
            'Request\'s url remains the original URL');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Request/response url attribute getter with redirect');

function evalJsonp(text) {
  return new Promise(function(resolve) {
      var report = resolve;
      // text must contain report() call.
      eval(text);
    });
}

async_test(function(t) {
    var request =
      new Request('/serviceworker/resources/fetch-access-control.php',
                  {
                    method: 'POST',
                    body: new Blob(['Test Blob'], {type: 'test/type'})
                  });
    fetch(request)
      .then(function(response) { return response.text(); })
      .then(evalJsonp)
      .then(function(result) {
          assert_equals(result.method, 'POST');
          assert_equals(result.body, 'Test Blob');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch with Blob body test');

async_test(function(t) {
    var request = new Request(
      '/serviceworker/resources/fetch-access-control.php',
      {method: 'POST', body: 'Test String'});
    fetch(request)
      .then(function(response) { return response.text(); })
      .then(evalJsonp)
      .then(function(result) {
          assert_equals(result.method, 'POST');
          assert_equals(result.body, 'Test String');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch with string body test');

async_test(function(t) {
    var text = 'Test ArrayBuffer';
    var array = new Uint8Array(text.length);
    for (var i = 0; i < text.length; ++i)
      array[i] = text.charCodeAt(i);
    var request = new Request(
      '/serviceworker/resources/fetch-access-control.php',
      {method: 'POST', body: array.buffer});
    fetch(request)
      .then(function(response) { return response.text(); })
      .then(evalJsonp)
      .then(function(result) {
          assert_equals(result.method, 'POST');
          assert_equals(result.body, 'Test ArrayBuffer');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch with ArrayBuffer body test');

async_test(function(t) {
    var text = 'Test ArrayBufferView';
    var array = new Uint8Array(text.length);
    for (var i = 0; i < text.length; ++i)
      array[i] = text.charCodeAt(i);
    var request = new Request(
      '/serviceworker/resources/fetch-access-control.php',
      {method: 'POST', body: array});
    fetch(request)
      .then(function(response) { return response.text(); })
      .then(evalJsonp)
      .then(function(result) {
          assert_equals(result.method, 'POST');
          assert_equals(result.body, 'Test ArrayBufferView');
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch with ArrayBufferView body test');

async_test(function(t) {
    var formData = new FormData();
    formData.append('StringKey1', '1234567890');
    formData.append('StringKey2', 'ABCDEFGHIJ');
    formData.append('BlobKey', new Blob(['blob content']));
    formData.append('FileKey',
                    new File(['file content'], 'file.dat'));
    var request = new Request(
      '/serviceworker/resources/fetch-access-control.php',
      {method: 'POST', body: formData});
    fetch(request)
      .then(function(response) { return response.text(); })
      .then(evalJsonp)
      .then(function(result) {
          assert_equals(result.method, 'POST');
          assert_equals(result.post['StringKey1'], '1234567890');
          assert_equals(result.post['StringKey2'], 'ABCDEFGHIJ');
          var files = [];
          for (var i = 0; i < result.files.length; ++i) {
            files[result.files[i].key] = result.files[i];
          }
          assert_equals(files['BlobKey'].content, 'blob content');
          assert_equals(files['BlobKey'].name, 'blob');
          assert_equals(files['BlobKey'].size, 12);
          assert_equals(files['FileKey'].content, 'file content');
          assert_equals(files['FileKey'].name, 'file.dat');
          assert_equals(files['FileKey'].size, 12);
          t.done();
        })
      .catch(unreached_rejection(t));
  }, 'Fetch with FormData body test');

test(function(t) {
    function runInfiniteFetchLoop() {
      fetch('dummy.html')
        .then(function() { runInfiniteFetchLoop(); });
    }
    runInfiniteFetchLoop();
  },
  'Destroying the execution context while fetch is happening should not ' +
  'cause a crash.');

done();
<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------
// MIT License
//
// Copyright (c) 2016 Philippe Leprince
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ----------------------------------------------------------------------------

function checkPrefs() {
    var all_valid = true
    if (alg.settings.value("RMANTREE") == undefined) {
        all_valid = false
        alg.log.warn("RMANTREE = " + alg.settings.value("RMANTREE"))
    }
    if (alg.settings.value("RMSTREE") == undefined) {
        all_valid = false
        alg.log.warn("RMSTREE = " + alg.settings.value("RMSTREE"))
    }
    if (alg.settings.value("saveTo") == undefined) {
        all_valid = false
        alg.log.warn("saveTo = " + alg.settings.value("saveTo"))
    }
    return all_valid
}

// FIXME: the bxdf param is currently ignored.

function exportAssets(bxdf) {

    // bail out if the prefs are not all filled
    //
    var valid = checkPrefs()
    if (!valid) {
        alg.log.error("RenderMan: Please open the configure panel and fill all fields !")
        return
    }

    // Some useful variables
    //
    var sep = "/"
    var pyBin = "python"
    var winOS = (Qt.platform.os == "windows")
    if (winOS) {
        sep = "\\"
        pyBin += ".exe"
    }
    var ext = ".png"
    var script = "rmanAssetsSubstancePainter.py"
    var exportPath = ""
    var jsonFilePath = ""
    var tab = "    "
    var tab2 = tab + tab
    var tab3 = tab2 + tab
    var tab4 = tab3 + tab

    // Query export path
    //
    exportPath = alg.mapexport.exportPath()
    if (winOS) {
        var tmp = new String(exportPath)
        exportPath = tmp.replace(/\//g, "\\")
        // alg.log.info("[WIN] exportPath = " + exportPath)
    }
    exportPath += sep + "RenderMan" + sep
    jsonFilePath = exportPath + "RmanExport.json"

    // Export masks
    //
    var matIdx = 0
    var channelIdx = 0
    var document = alg.mapexport.documentStructure()
    var fileContent = "{\n"

    // store env vars
    //
    fileContent += tab + "\"RMANTREE\": \"" + alg.settings.value("RMANTREE") + "\",\n"
    fileContent += tab + "\"RMSTREE\": \"" + alg.settings.value("RMSTREE") + "\",\n"
    fileContent += tab + "\"saveTo\": \"" + alg.settings.value("saveTo") + "\",\n"
    fileContent += tab + "\"document\": [\n"

    // Parse all materials (texture sets)
    //
    for (matIdx = 0; matIdx < document.materials.length; matIdx++) {
        var material = document.materials[matIdx].name
        fileContent += tab2 + "{\n"
        fileContent += tab3 + "\"textureSet\": \"" + material + "\",\n"
        fileContent += tab3 + "\"channels\": {\n"
        // alg.log.info("RenderMan: Texture Set \"" + material + "\" : ")

        var numChannels = document.materials[matIdx].stacks[0].channels.length
        for (channelIdx = 0; channelIdx < numChannels; channelIdx++) {
            var thisChannel = document.materials[matIdx].stacks[0].channels[channelIdx]
            // alg.log.info("RenderMan:   | " + thisChannel)

            var output = exportPath + material + "_" + thisChannel + ext

            var materials = []
            materials[0] = material
            materials[1] = thisChannel

            alg.mapexport.save(materials, output)
            // alg.log.info("RenderMan:   |_ Exported : " + output)

            // Prepare Data for json file
            //
            fileContent += tab4 + "\"" + thisChannel + "\": \"" + output + "\""
            if (channelIdx < numChannels - 1)
                fileContent += ",\n"
            else
                fileContent += "\n"
        }
        if (matIdx < document.materials.length - 1)
            fileContent += tab3 + "}\n" + tab2 + "},\n"
        else
            fileContent += tab3 + "}\n" + tab2 + "}\n"
    }
    fileContent += tab + "]\n}\n"

    // Write json file and export
    //
    if (fileContent.length > 0) {
        alg.log.info("RenderMan: Writing " + jsonFilePath + "...")

        // write json file needed by the python script
        //
        var jsonFile = alg.fileIO.open(jsonFilePath, "w")
        jsonFile.write(fileContent)
        jsonFile.close()

        // Call python
        // FIXME: we should probably just catch exceptions and print the log on error.
        //
        var fpath = "\"" + jsonFilePath + "\""
        var result = alg.subprocess.check_output([pyBin, script, fpath])
        alg.log.info("RenderMan: Python : " + result)
    }
    else {
        alg.log.error("RenderMan: Nothing to export !")
    }
    alg.log.info("RenderMan: Export successful ! :)")
}

<commit_msg>windows file paths were not correctly serialized to json.<commit_after>// ----------------------------------------------------------------------------
// MIT License
//
// Copyright (c) 2016 Philippe Leprince
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ----------------------------------------------------------------------------

function osPath(input_path) {
    var platformPath = input_path
    if (Qt.platform.os == "windows") {
        var tmp = new String(platformPath)
        platformPath = tmp.replace(/\//g, "\\")
        // alg.log.info("[WIN] platformPath = " + platformPath)
    }
    return platformPath
}

function jsonPath(input_path) {
    var jsnPath = input_path
    if (Qt.platform.os == "windows") {
        var tmp = new String(jsnPath)
        jsnPath = tmp.replace(/\\/g, "\\\\")
        // alg.log.info("[WIN] jsnPath = " + jsnPath)
    }
    return jsnPath
}

function checkPrefs() {
    var all_valid = true
    if (alg.settings.value("RMANTREE") == undefined) {
        all_valid = false
        alg.log.warn("RMANTREE = " + alg.settings.value("RMANTREE"))
    }
    if (alg.settings.value("RMSTREE") == undefined) {
        all_valid = false
        alg.log.warn("RMSTREE = " + alg.settings.value("RMSTREE"))
    }
    if (alg.settings.value("saveTo") == undefined) {
        all_valid = false
        alg.log.warn("saveTo = " + alg.settings.value("saveTo"))
    }
    return all_valid
}

// FIXME: the bxdf param is currently ignored.

function exportAssets(bxdf) {

    // bail out if the prefs are not all filled
    //
    var valid = checkPrefs()
    if (!valid) {
        alg.log.error("RenderMan: Please open the configure panel and fill all fields !")
        return
    }

    // Some useful variables
    //
    var sep = "/"
    var pyBin = "python"
    var winOS = (Qt.platform.os == "windows")
    if (winOS) {
        sep = "\\"
        pyBin += ".exe"
    }
    var ext = ".png"
    var script = "rmanAssetsSubstancePainter.py"
    var exportPath = ""
    var jsonFilePath = ""
    var tab = "    "
    var tab2 = tab + tab
    var tab3 = tab2 + tab
    var tab4 = tab3 + tab

    // Query export path
    //
    exportPath = osPath(alg.mapexport.exportPath())
    exportPath += sep + "RenderMan" + sep
    jsonFilePath = exportPath + "RmanExport.json"

    // Export masks
    //
    var matIdx = 0
    var channelIdx = 0
    var document = alg.mapexport.documentStructure()
    var fileContent = "{\n"

    // store env vars
    //
    fileContent += tab + "\"RMANTREE\": \"" + jsonPath(alg.settings.value("RMANTREE")) + "\",\n"
    fileContent += tab + "\"RMSTREE\": \"" + jsonPath(alg.settings.value("RMSTREE")) + "\",\n"
    fileContent += tab + "\"saveTo\": \"" + jsonPath(alg.settings.value("saveTo")) + "\",\n"
    fileContent += tab + "\"document\": [\n"

    // Parse all materials (texture sets)
    //
    for (matIdx = 0; matIdx < document.materials.length; matIdx++) {
        var material = document.materials[matIdx].name
        fileContent += tab2 + "{\n"
        fileContent += tab3 + "\"textureSet\": \"" + material + "\",\n"
        fileContent += tab3 + "\"channels\": {\n"
        // alg.log.info("RenderMan: Texture Set \"" + material + "\" : ")

        var numChannels = document.materials[matIdx].stacks[0].channels.length
        for (channelIdx = 0; channelIdx < numChannels; channelIdx++) {
            var thisChannel = document.materials[matIdx].stacks[0].channels[channelIdx]
            // alg.log.info("RenderMan:   | " + thisChannel)

            var output = exportPath + material + "_" + thisChannel + ext

            var materials = []
            materials[0] = material
            materials[1] = thisChannel

            alg.mapexport.save(materials, output)
            // alg.log.info("RenderMan:   |_ Exported : " + output)

            // Prepare Data for json file
            //
            fileContent += tab4 + "\"" + thisChannel + "\": \"" + jsonPath(output) + "\""
            if (channelIdx < numChannels - 1)
                fileContent += ",\n"
            else
                fileContent += "\n"
        }
        if (matIdx < document.materials.length - 1)
            fileContent += tab3 + "}\n" + tab2 + "},\n"
        else
            fileContent += tab3 + "}\n" + tab2 + "}\n"
    }
    fileContent += tab + "]\n}\n"

    // Write json file and export
    //
    if (fileContent.length > 0) {
        alg.log.info("RenderMan: Writing " + jsonFilePath + "...")

        // write json file needed by the python script
        //
        var jsonFile = alg.fileIO.open(jsonFilePath, "w")
        jsonFile.write(fileContent)
        jsonFile.close()

        // Call python
        // FIXME: we should probably just catch exceptions and print the log on error.
        //
        var fpath = "\"" + jsonFilePath + "\""
        var result = alg.subprocess.check_output([pyBin, script, fpath])
        alg.log.info("RenderMan: Python : " + result)
    }
    else {
        alg.log.error("RenderMan: Nothing to export !")
    }
    alg.log.info("RenderMan: Export successful ! :)")
}

<|endoftext|>


<commit_before>// ==UserScript==
// @name         Slack Full Theme plugin
// @namespace    http://mrkannah.com/
// @version      1.0.1
// @description  Applies the side bar colors for slack to the entire application
// @author       Fadee Kannah
// @match        https://*.slack.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-end
// ==/UserScript==

$(document).ready(function(){
    var checkInterval = setInterval(function(){
        if(Ready()){
            var colors = GM_getValue('ST_Colors');
            clearInterval(checkInterval);
            if(colors){
                applyColors(colors);
                setUp(colors)
            }
            else{
                setTimeout(function(){
                    colors = getColors();
                    setTimeout(setUp(colors),300);
                },100);
            }
        }
    },200);
});

function setUp(colors){
    applyColors(colors);
    addListner();
}

function Ready(){
    return parseInt($('#loading_welcome').css('opacity')) ? 0 : 1;
}

function getColors(){
    $('#team_menu')[0].click();
    $('#member_prefs_item > a')[0].click();
    var colors = $('#sidebar_theme_custom').val().toString().split(',');
    $('.dialog_go ')[0].click();
    return colors;
    /* Array Index
0 Col BG
1 Menu BG
2 Active Item
3 Active Text
4 Hover Item
5 Text Color
6 Active precesne
7 mention Badge
*/
}

function applyColors(colors){
    GM_setValue('ST_Colors',colors);
    console.log(colors);
    var head = document.getElementsByTagName('head')[0];
    var style = document.createElement('style');
    style.type = 'text/css';
    style.id = 'fullThemePlugin';

    //header & footer styles
    style.innerHTML = '#header{ background:'+colors[1]+'}' +
        '#end_div{background:'+colors[1]+'}' +
        '#channel_members_toggle{ background:'+colors[1]+'!important}'+
        '#footer{background:'+colors[0]+'}'+
        '#primary_file_button:hover {background:'+colors[4]+';color: '+colors[5]+';border-color:'+colors[4]+'}';

    //divier styles
    style.innerHTML +='.day_divider{background:'+colors[0]+' !important}' +
        '.day_divider_label{background:'+colors[0] +'!important;color:'+colors[3]+'}';

    //messages styles
    style.innerHTML += '.msgs_holder{background:'+colors[0]+'}'+
        '.mention{color:'+colors[1]+';background:'+colors[7]+'!important}' +
        '.light_theme .message_sender {color:'+colors[3]+' !important}' +
        '.message_content{color:'+colors[5]+'}';

    //Global Styles
    style.innerHTML += 'a{color:'+colors[2]+'!important}'+
        '.msg_inline_file_preview_title{color:'+colors[2]+'!important}'+
        'body{background:'+colors[0]+'}';

    //scroll bar styles
    style.innerHTML += '.monkey_scroll_handle_inner{background:'+colors[2]+'!important;border:0!important}' +
        '.monkey_scroll_handle{position:relative;left:-1px!important;width:10px!important}';

    head.appendChild(style);

    return $(style);

}

function addListner(){
    $('#team_menu').on('click',function(){
        $('#member_prefs_item > a').on('click',function(){
            setTimeout(function(){
                $('.color_hex').on('input',function(){
                    changeColors();
                });
                $('input[name="sidebar_theme_rd"]').on('change',function(){
                    changeColors();
                });
                $('#sidebar_theme_custom').on('input change',function() {
                    changeColors();
                });
                $('.color_swatch').on('click', function(){
                    setTimeout(function(){
                        changeColors();
                    },700);
                });
            },500);
        });
    });
}

function changeColors(){
    var colors = $('#sidebar_theme_custom').val().split(',');
    $('#fullThemePlugin').remove();
    applyColors(colors);
}
<commit_msg>Version bump to V1.0.2<commit_after>// ==UserScript==
// @name         Slack Full Theme plugin
// @namespace    http://mrkannah.com/
// @version      1.0.2
// @description  Applies the side bar colors for slack to the entire application
// @author       Fadee Kannah
// @match        https://*.slack.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-end
// ==/UserScript==

$(document).ready(function(){
    var checkInterval = setInterval(function(){
        if(Ready()){
            var colors = GM_getValue('ST_Colors');
            clearInterval(checkInterval);
            if(colors){
                applyColors(colors);
                setUp(colors)
            }
            else{
                setTimeout(function(){
                    colors = getColors();
                    setTimeout(setUp(colors),300);
                },100);
            }
        }
    },200);
});

function setUp(colors){
    applyColors(colors);
    addListner();
}

function Ready(){
    return parseInt($('#loading_welcome').css('opacity')) ? 0 : 1;
}

function getColors(){
    $('#team_menu')[0].click();
    $('#member_prefs_item > a')[0].click();
    var colors = $('#sidebar_theme_custom').val().toString().split(',');
    $('.dialog_go ')[0].click();
    return colors;
    /* Array Index
0 Col BG
1 Menu BG
2 Active Item
3 Active Text
4 Hover Item
5 Text Color
6 Active precesne
7 mention Badge
*/
}

function applyColors(colors){
    GM_setValue('ST_Colors',colors);
    console.log(colors);
    var head = document.getElementsByTagName('head')[0];
    var style = document.createElement('style');
    style.type = 'text/css';
    style.id = 'fullThemePlugin';

    //header & footer styles
    style.innerHTML = '#header{ background:'+colors[1]+'}' +
        '#end_div{background:'+colors[1]+'}' +
        '#channel_members_toggle{ background:'+colors[1]+'!important}'+
        '#footer{background:'+colors[0]+'}'+
        '#primary_file_button:hover {background:'+colors[4]+';color: '+colors[5]+';border-color:'+colors[4]+'}';

    //divier styles
    style.innerHTML +='.day_divider{background:'+colors[0]+' !important}' +
        '.day_divider_label{background:'+colors[0] +'!important;color:'+colors[3]+'}';

    //messages styles
    style.innerHTML += '.msgs_holder{background:'+colors[0]+'}'+
        '.mention{color:'+colors[1]+';background:'+colors[7]+'!important}' +
        '.light_theme .message_sender {color:'+colors[3]+' !important}' +
        '.message_content{color:'+colors[5]+'}';

    //Global Styles
    style.innerHTML += 'a{color:'+colors[2]+'!important}'+
        '.msg_inline_file_preview_title{color:'+colors[2]+'!important}'+
        'body{background:'+colors[0]+'}';

    //scroll bar styles
    style.innerHTML += '.monkey_scroll_handle_inner{background:'+colors[2]+'!important;border:0!important}' +
        '.monkey_scroll_handle{position:relative;left:-1px!important;width:10px!important}';

    head.appendChild(style);

    return $(style);

}

function addListner(){
    $('#team_menu').on('click',function(){
        $('#member_prefs_item > a').on('click',function(){
            setTimeout(function(){
                $('.color_hex').on('input',function(){
                    changeColors();
                });
                $('input[name="sidebar_theme_rd"]').on('change',function(){
                    changeColors();
                });
                $('#sidebar_theme_custom').on('input change',function() {
                    changeColors();
                });
                $('.color_swatch').on('click', function(){
                    setTimeout(function(){
                        changeColors();
                    },700);
                });
            },500);
        });
    });
}

function changeColors(){
    var colors = $('#sidebar_theme_custom').val().split(',');
    $('#fullThemePlugin').remove();
    applyColors(colors);
}
<|endoftext|>