<commit_before>/*ConnextCMS pluginView.js - This file loads plugins at run-time.*/
define([
	'jQuery-2.1.4.min',
	'underscore_1.3.3',
	'backbone_0.9.2',
  'text!../../../js/app/templates/pluginTemplate.html'
], function ($, _, Backbone, PluginTemplate) {
	'use strict';

	var PostsView = Backbone.View.extend({

		tagName:  'div',

    el: '#pluginDiv',

		template: _.template(PluginTemplate),

		// The DOM events specific to an item.
		events: {

		},

		initialize: function () {
      this.loadedPlugins = []; //An array containing all the loaded plugins and their Backbone constructs.
      this.pluginData = []; //An array containing the contents of the pluginSettings.json file (the metadata) for each plugin.
		},

    render: function () {
      //debugger;

      var thisView = this;

      this.$el.html(this.template);

      $.get('/api/plugins/list', '', function(data) {
        //debugger;

        //Error Handling
        if( (!data.success) || (data.plugins.length == 0) ) {
          return;
        }

        //Save the pluginSettings.json data
        thisView.pluginData = data.plugins; //Copy the plugin data (for all plugins) to the Plugin View
        var pluginData = data.plugins;      //Also copy the plugin data to a local variable.

        //Loop through each PLUGIN
        for(var i=0; i < pluginData.length; i++) {

          //Add a div to the DOM. This will be the div for the current plugin.
          thisView.$el.find('#pluginParentDiv').append('

');

          //Tell the plugin which div belongs to it.
          thisView.pluginData[i].divId = '#plugin'+i;

          //Prep the loadedPlugins object for this plugin with an empty object.
          var tmpObj = {};
          tmpObj.views = [];
          tmpObj.models = [];
          tmpObj.collections = [];
          thisView.loadedPlugins[i] = tmpObj;

          //Load the Backbone Views, Models, and Collections associated with this plugin.
          thisView.loadViews(i);

          thisView.loadModels(i);
        }

      });

			return this;
		},

    //This function instantiates the Backbone Views, Models, and Collections associated with a plugin.
    //It expects the plugin metadata to be passed into it. This is the data stored in the pluginSettings.json
    loadViews: function(pluginIndex) {
      //debugger;

      //Get local handles to view-level objects.
      var thisView = this;                                //Get a handle on this View.
      var thisPluginData = this.pluginData[pluginIndex];  //Plugin Metadata
      var thisPlugin = this.loadedPlugins[pluginIndex];   //Will hold the plugins Backbone constructs.

      // ---BEGIN BACKBONE VIEWS---

      //Loop through each of the backbone views for this plugin.
      //Have to use an async for loop since we making async calls to $.getScript().
      global.async.eachOf(thisPluginData.backboneViewFiles, function(value, key, callback) {
        //debugger;

        try {

          var pluginDir = '/plugins/'+thisPluginData.pluginDirName+'/';

          //Load the individual views for this plugin. Generate a promise for each view.
          var scriptPromise = $.getScript(pluginDir+value, function(data, textStatus, jqxhr) {
            //debugger;

          })
          .fail(function( jqxhr, settings, exception ) {
            debugger;

            console.error('Problem with pluginView.js/loadViews() when trying load Backbone Views: '+exception);
          });

          //When the promise resolves:
          scriptPromise.then(function(results) {
            //debugger;

            //Scope is lost at the point and a handle needs to be established on the current plugin.
            var thisPluginIndex = global.pluginView.getPluginIndex('backboneViewNames', results);
            if(thisPluginIndex == null) {
              console.error('Could not find plugin.');
              return;
            } else {
              var thisPluginData = global.pluginView.pluginData[thisPluginIndex];
              var thisPlugin = global.pluginView.loadedPlugins[thisPluginIndex];
            }

            //Create the new view.
            var constructor = "new "+thisPluginData.backboneViewNames[key]+"({el: $(thisPluginData.divId), pluginData: thisPluginData, pluginHandle: thisPlugin })";
            var thisView = eval(constructor);

            //Add this view to the loadedPlugins.views[] array.
            thisPlugin.views.push(thisView);

            //Create a global reference to the primary view that should be loaded when the user
            //clicks on the left menu entry for this plugin.
            if(thisPluginData.primaryViewConstructor == thisPluginData.backboneViewNames[key]) {

              var pluginViewReference = "global.pluginView."+thisPluginData.primaryViewInstance;
              var evalStr = pluginViewReference+" = thisPlugin.views["+key+"]";
              eval(evalStr);

              //Add a menu item for this primary view.
              var tmpLi = '
 '+thisPluginData.primaryViewLabel+'
';
              var pluginLi = global.leftMenuView.$el.find('#plugin-link');
              pluginLi.parent().append(tmpLi);
            }

            //debugger;
            //loadModels();
            //callback();

          }, function(error) {
            debugger;
            callback(error);
          });

        } catch(err) {
          callback(err);
        }

      }, function(err) {
        debugger;

        if(err) {
          debugger;
          console.error('Problem with pluginView.js/loadViews() when trying to load Backbone Views: '+err);
        } else {
          debugger;

          //Views have been loaded. Next, load the models.
          //global.pluginView.loadModels();
        }

      });
      // ---END BACKBONE VIEWS---

    },

    // ---BEGIN BACKBONE MODELS---

    //This function is called in parallel with loadViews(). It's purpose is to load the
    //Backbone models associated with this plugin.
    loadModels: function(pluginIndex) {
      debugger;

      //Get local handles to view-level objects.
      var thisView = this;                                //Get a handle on this View.
      var thisPluginData = this.pluginData[pluginIndex];  //Plugin Metadata
      var thisPlugin = this.loadedPlugins[pluginIndex];   //Will hold the plugins Backbone constructs.

      //Loop through each of the backbone views for this plugin.
      //Have to use an async for loop since we making async calls to $.getScript().
      global.async.eachOf(thisPluginData.backboneModelFiles, function(value, key, callback) {
        try {

          var pluginDir = '/plugins/'+thisPluginData.pluginDirName+'/';

          //Load the individual views for this plugin. Generate a promise for each view.
          var scriptPromise = $.getScript(pluginDir+value, function(data, textStatus, jqxhr) {

          })
          .fail(function( jqxhr, settings, exception ) {
            debugger;

            console.error('Problem with pluginView.js/loadModels() when trying load Backbone Models: '+exception);
            callback(exception);
          });

          //When the promise resolves:
          scriptPromise.then(function(results) {
            debugger;

            //Scope is lost at the point and a handle needs to be established on the current plugin.
            var thisPluginIndex = global.pluginView.getPluginIndex('backboneModelNames', results);
            if(thisPluginIndex == null) {
              console.error('Could not find plugin.');
              return;
            } else {
              var thisPluginData = global.pluginView.pluginData[thisPluginIndex];
              var thisPlugin = global.pluginView.loadedPlugins[thisPluginIndex];
            }

            var constructor = "new "+thisPluginData.modelNames[key]+"(null,{pluginData: thisPluginData, pluginHandle: thisPlugin })";
            var thisModel = eval(constructor);

            thisPlugin.models.push(thisModel);

          }, function(err) {
            debugger;
            callback(err);
          });

        } catch(err) {
          callback(err);
        }

      }, function(err) {
        debugger;

        if(err) {
          debugger;
          console.error('Problem with pluginView.js/loadModels() when trying to load Backbone Models: '+err);
        } else {
          debugger;

          //Views have been loaded. Next, load the models.
          //global.pluginView.loadModels();
        }

      });
    },

    // ---END BACKBONE MODELS---

    // ---BEGIN UTILITY FUNCTIONS---

    //Dev note: I don't think this function is used any more.
    //This function returns a pointer to the global.pluginView.loadedPlugins[] element
    //that matches the directory name stored in that plugins metadata. It's useful for
    //getting the plugin constructs in a function without any scope.
    //If the loaded plugin can not be found, then this functioin returns false.
    getHandle: function(dirName) {
      try {
        debugger;

        for(var i=0; i < global.pluginView.pluginData.length; i++) {
          if(dirName == global.pluginView.pluginData[i].pluginDirName) {
            return global.pluginView.loadedPlugins[i];
          }
        }

        return false;

      } catch(err) {
          console.error('Problem in pluginView.js/getHandle(): '+err);
      }
    },

    //This function is used to retrieve the plugin index -e.g. which plugin inside
    //global.pluginView.pluginData that we're trying to deal with. It returns
    //the element inside the global.pluginView.pluginData array that matches the
    //key and script. If no match is found, it returns null.
    //This function is used to regain scope on the currently targeted plugin.
    //
    //Since this function uses text matching, it can cause a false positive when
    //text in the Backbone files are copied from the template. If this because
    //a serious issue, I might want to think of ways to refine this function.
    getPluginIndex: function(key, script) {
      //debugger;

      try {
        var thisPluginIndex = null;

        //Loop through each plugin's metadata.
        for(var i=0; i < global.pluginView.pluginData.length; i++) {

          //Loop through each element in the key field.
          var keyArray = eval('global.pluginView.pluginData[i].'+key);

          for(var j=0; j < keyArray.length; j++) {
            if(script.indexOf(keyArray[j]) > -1) {
              console.log('pluginView.js/getPluginIndex() found a match with '+keyArray[j]);
              thisPluginIndex = i;
              return thisPluginIndex;
            }
          }
        }

        if(thisPluginIndex == null) {
          debugger;
          console.error('Problem in pluginView.js/getPluginIndex(). Could not identify the view and could not find the plugin index. key = '+key);
          return null;
        }

      } catch(err) {
        debugger;
        console.log('Error in getPluginIndex(): '+err);
        return null;
      }
    }

    // ---END UTILITY FUNCTIONS---

	});

  //debugger;
	return PostsView;
});<commit_msg>Importing pluginLoader.js code into pluginView.js<commit_after>/*ConnextCMS pluginView.js - This file loads plugins at run-time.*/
define([
	'jQuery-2.1.4.min',
	'underscore_1.3.3',
	'backbone_0.9.2',
  'text!../../../js/app/templates/pluginTemplate.html'
], function ($, _, Backbone, PluginTemplate) {
	'use strict';

	var PostsView = Backbone.View.extend({

		tagName:  'div',

    el: '#pluginDiv',

		template: _.template(PluginTemplate),

		// The DOM events specific to an item.
		events: {

		},

		initialize: function () {
      this.loadedPlugins = []; //An array containing all the loaded plugins and their Backbone constructs.
      this.pluginData = []; //An array containing the contents of the pluginSettings.json file (the metadata) for each plugin.
		},

    render: function () {
      //debugger;

      var thisView = this;

      this.$el.html(this.template);

      $.get('/api/plugins/list', '', function(data) {
        //debugger;

        //Error Handling
        if( (!data.success) || (data.plugins.length == 0) ) {
          return;
        }

        //Save the pluginSettings.json data
        thisView.pluginData = data.plugins; //Copy the plugin data (for all plugins) to the Plugin View
        var pluginData = data.plugins;      //Also copy the plugin data to a local variable.

        //Loop through each PLUGIN
        for(var i=0; i < pluginData.length; i++) {

          //Add a div to the DOM. This will be the div for the current plugin.
          thisView.$el.find('#pluginParentDiv').append('

');

          //Tell the plugin which div belongs to it.
          thisView.pluginData[i].divId = '#plugin'+i;

          //Prep the loadedPlugins object for this plugin with an empty object.
          var tmpObj = {};
          tmpObj.views = [];
          tmpObj.models = [];
          tmpObj.collections = [];
          thisView.loadedPlugins[i] = tmpObj;

          //Load the Backbone Views, Models, and Collections associated with this plugin.
          thisView.loadViews(i);

          thisView.loadModels(i);
        }

      });

			return this;
		},

    //This function instantiates the Backbone Views, Models, and Collections associated with a plugin.
    //It expects the plugin metadata to be passed into it. This is the data stored in the pluginSettings.json
    loadViews: function(pluginIndex) {
      //debugger;

      //Get local handles to view-level objects.
      var thisView = this;                                //Get a handle on this View.
      var thisPluginData = this.pluginData[pluginIndex];  //Plugin Metadata
      var thisPlugin = this.loadedPlugins[pluginIndex];   //Will hold the plugins Backbone constructs.

      // ---BEGIN BACKBONE VIEWS---

      //Loop through each of the backbone views for this plugin.
      //Have to use an async for loop since we making async calls to $.getScript().
      global.async.eachOf(thisPluginData.backboneViewFiles, function(value, key, callback) {
        //debugger;

        try {

          var pluginDir = '/plugins/'+thisPluginData.pluginDirName+'/';

          //Load the individual views for this plugin. Generate a promise for each view.
          var scriptPromise = $.getScript(pluginDir+value, function(data, textStatus, jqxhr) {
            //debugger;

          })
          .fail(function( jqxhr, settings, exception ) {
            debugger;

            console.error('Problem with pluginView.js/loadViews() when trying load Backbone Views: '+exception);
          });

          //When the promise resolves:
          scriptPromise.then(function(results) {
            //debugger;

            //Scope is lost at the point and a handle needs to be established on the current plugin.
            var thisPluginIndex = global.pluginView.getPluginIndex('backboneViewNames', results);
            if(thisPluginIndex == null) {
              console.error('Could not find plugin.');
              return;
            } else {
              var thisPluginData = global.pluginView.pluginData[thisPluginIndex];
              var thisPlugin = global.pluginView.loadedPlugins[thisPluginIndex];
            }

            //Create the new view.
            var constructor = "new "+thisPluginData.backboneViewNames[key]+"({el: $(thisPluginData.divId), pluginData: thisPluginData, pluginHandle: thisPlugin })";
            var thisView = eval(constructor);

            //Add this view to the loadedPlugins.views[] array.
            thisPlugin.views.push(thisView);

            //Create a global reference to the primary view that should be loaded when the user
            //clicks on the left menu entry for this plugin.
            if(thisPluginData.primaryViewConstructor == thisPluginData.backboneViewNames[key]) {

              var pluginViewReference = "global.pluginView."+thisPluginData.primaryViewInstance;
              var evalStr = pluginViewReference+" = thisPlugin.views["+key+"]";
              eval(evalStr);

              //Add a menu item for this primary view.
              var tmpLi = '
 '+thisPluginData.primaryViewLabel+'
';
              var pluginLi = global.leftMenuView.$el.find('#plugin-link');
              pluginLi.parent().append(tmpLi);
            }

            //debugger;
            //loadModels();
            //callback();

          }, function(error) {
            debugger;
            callback(error);
          });

        } catch(err) {
          callback(err);
        }

      }, function(err) {
        debugger;

        if(err) {
          debugger;
          console.error('Problem with pluginView.js/loadViews() when trying to load Backbone Views: '+err);
        } else {
          debugger;

          //Views have been loaded. Next, load the models.
          //global.pluginView.loadModels();
        }

      });
      // ---END BACKBONE VIEWS---

    },

    // ---BEGIN BACKBONE MODELS---

    //This function is called in parallel with loadViews(). It's purpose is to load the
    //Backbone models associated with this plugin.
    loadModels: function(pluginIndex) {
      debugger;

      //Get local handles to view-level objects.
      var thisView = this;                                //Get a handle on this View.
      var thisPluginData = this.pluginData[pluginIndex];  //Plugin Metadata
      var thisPlugin = this.loadedPlugins[pluginIndex];   //Will hold the plugins Backbone constructs.

      //Loop through each of the backbone views for this plugin.
      //Have to use an async for loop since we making async calls to $.getScript().
      global.async.eachOf(thisPluginData.backboneModelFiles, function(value, key, callback) {
        try {

          var pluginDir = '/plugins/'+thisPluginData.pluginDirName+'/';

          //Load the individual views for this plugin. Generate a promise for each view.
          var scriptPromise = $.getScript(pluginDir+value, function(data, textStatus, jqxhr) {

          })
          .fail(function( jqxhr, settings, exception ) {
            debugger;

            console.error('Problem with pluginView.js/loadModels() when trying load Backbone Models: '+exception);
            callback(exception);
          });

          //When the promise resolves:
          scriptPromise.then(function(results) {
            debugger;

            //Scope is lost at the point and a handle needs to be established on the current plugin.
            var thisPluginIndex = global.pluginView.getPluginIndex('backboneModelNames', results);
            if(thisPluginIndex == null) {
              console.error('Could not find plugin.');
              return;
            } else {
              var thisPluginData = global.pluginView.pluginData[thisPluginIndex];
              var thisPlugin = global.pluginView.loadedPlugins[thisPluginIndex];
            }

            var constructor = "new "+thisPluginData.backboneModelNames[key]+"(null,{pluginData: thisPluginData, pluginHandle: thisPlugin })";
            var thisModel = eval(constructor);

            thisPlugin.models.push(thisModel);

          }, function(err) {
            debugger;
            callback(err);
          });

        } catch(err) {
          callback(err);
        }

      }, function(err) {
        debugger;

        if(err) {
          debugger;
          console.error('Problem with pluginView.js/loadModels() when trying to load Backbone Models: '+err);
        } else {
          debugger;

          //Views have been loaded. Next, load the models.
          //global.pluginView.loadModels();
        }

      });
    },

    // ---END BACKBONE MODELS---

    // ---BEGIN UTILITY FUNCTIONS---

    //Dev note: I don't think this function is used any more.
    //This function returns a pointer to the global.pluginView.loadedPlugins[] element
    //that matches the directory name stored in that plugins metadata. It's useful for
    //getting the plugin constructs in a function without any scope.
    //If the loaded plugin can not be found, then this functioin returns false.
    getHandle: function(dirName) {
      try {
        debugger;

        for(var i=0; i < global.pluginView.pluginData.length; i++) {
          if(dirName == global.pluginView.pluginData[i].pluginDirName) {
            return global.pluginView.loadedPlugins[i];
          }
        }

        return false;

      } catch(err) {
          console.error('Problem in pluginView.js/getHandle(): '+err);
      }
    },

    //This function is used to retrieve the plugin index -e.g. which plugin inside
    //global.pluginView.pluginData that we're trying to deal with. It returns
    //the element inside the global.pluginView.pluginData array that matches the
    //key and script. If no match is found, it returns null.
    //This function is used to regain scope on the currently targeted plugin.
    //
    //Since this function uses text matching, it can cause a false positive when
    //text in the Backbone files are copied from the template. If this because
    //a serious issue, I might want to think of ways to refine this function.
    getPluginIndex: function(key, script) {
      //debugger;

      try {
        var thisPluginIndex = null;

        //Loop through each plugin's metadata.
        for(var i=0; i < global.pluginView.pluginData.length; i++) {

          //Loop through each element in the key field.
          var keyArray = eval('global.pluginView.pluginData[i].'+key);

          for(var j=0; j < keyArray.length; j++) {
            if(script.indexOf(keyArray[j]) > -1) {
              console.log('pluginView.js/getPluginIndex() found a match with '+keyArray[j]);
              thisPluginIndex = i;
              return thisPluginIndex;
            }
          }
        }

        if(thisPluginIndex == null) {
          debugger;
          console.error('Problem in pluginView.js/getPluginIndex(). Could not identify the view and could not find the plugin index. key = '+key);
          return null;
        }

      } catch(err) {
        debugger;
        console.log('Error in getPluginIndex(): '+err);
        return null;
      }
    }

    // ---END UTILITY FUNCTIONS---

	});

  //debugger;
	return PostsView;
});<|endoftext|>


<commit_before>var Store = require('../../lib/store')

describe.only('Error', function(){
  var store = new Store()

  store.Model('User', function(){
    this.hasMany('posts')
    this.belongsTo('avatar')
  })

  store.Model('Post', function(){
    this.attribute('title')
  })

  store.Model('Avatar', function(){
    this.attribute('url')
  })

  var User, phil, michl

  before(function(next){
    store.ready(function(){
      User = store.Model('User')
      phil = new User()
      michl = new User({
        posts: [{
          title: 'foo'
        }],

        avatar: {
          url: 'http://foo.com/img.png'
        }
      })
      next()
    })
  })

  describe('errors.add()', function(){
    it('add attribute error', function(){
      phil.errors.add('attribute_name', 'not valid')
    })

    it('add base error', function(){
      phil.errors.add('can not be deleted')
    })

    it('is an array of errors', function(){
      phil.errors['attribute_name'].should.be.an.instanceOf(Array)
      phil.errors['attribute_name'][0].should.be.equal('not valid')
    })

    it('has base errors', function(){
      phil.errors['base'].should.be.an.instanceOf(Array)
      phil.errors['base'][0].should.be.equal('can not be deleted')
    })

    it('throws an error on reserved word (add)', function(){
      (function(){
        phil.errors.add('add', 'msg')
      }).should.throw()
    })

    it('throws an error on reserved word (set)', function(){
      (function(){
        phil.errors.add('set', 'msg')
      }).should.throw()
    })

    it('throws an error on reserved word (each)', function(){
      (function(){
        phil.errors.add('each', 'msg')
      }).should.throw()
    })

    it('throws an error on reserved word (toJSON)', function(){
      (function(){
        phil.errors.add('toJSON', 'msg')
      }).should.throw()
    })
  })

  describe('errors.set()', function(){
    it('set multiple attributes', function(){
      phil.errors.set({
        a: 'Error a',
        b: 'Error b'
      })
      phil.errors.a.should.be.eql(['Error a'])
      phil.errors.b.should.be.eql(['Error b'])
    })
  })

  describe('errors.each()', function(){
    it('add attribute error', function(){
      const tmp = []
      phil.errors.each(function(field, error){
        tmp.push(field)
        tmp.push(error)
      })
      tmp.should.be.eql([
        'attribute_name',
        'not valid',
        'base',
        'can not be deleted',
        'a',
        'Error a',
        'b',
        'Error b'
      ])
    })
  })

  describe('errors.toJSON()', function(){
    it('returns the json representation', function(){
      phil.errors.toJSON().should.be.eql({
        attribute_name: [ 'not valid' ],
        a: ['Error a'],
        base: ['can not be deleted'],
        b: ['Error b']
      })
    })
  })

  describe('errors.toString()', function(){
    it('set converts all errors to a string', function(){
      phil.errors.toString().should.be.equal('attribute_name: not valid\ncan not be deleted\na: Error a\nb: Error b')
    })
  })

  describe('relation errors', function(){
    before(function(){
      michl.posts[0].errors.add('title', 'some title error')
      michl.avatar.errors.add('url', 'some url error')
    })

    it('has the posts error object on its error obj.', function(){
      michl.errors.should.have.property('posts')
    })

    it('has the avatar error object on its error obj.', function(){
      michl.errors.should.have.property('avatar')
    })

    it('errors is an array for hasMany', function(){
      michl.errors.posts.should.be.instanceOf(Array)
    })

    it('errors is an object for belongsTo', function(){
      michl.errors.avatar.should.not.be.instanceOf(Array)
    })
  })
})
<commit_msg>run all<commit_after>var Store = require('../../lib/store')

describe('Error', function(){
  var store = new Store()

  store.Model('User', function(){
    this.hasMany('posts')
    this.belongsTo('avatar')
  })

  store.Model('Post', function(){
    this.attribute('title')
  })

  store.Model('Avatar', function(){
    this.attribute('url')
  })

  var User, phil, michl

  before(function(next){
    store.ready(function(){
      User = store.Model('User')
      phil = new User()
      michl = new User({
        posts: [{
          title: 'foo'
        }],

        avatar: {
          url: 'http://foo.com/img.png'
        }
      })
      next()
    })
  })

  describe('errors.add()', function(){
    it('add attribute error', function(){
      phil.errors.add('attribute_name', 'not valid')
    })

    it('add base error', function(){
      phil.errors.add('can not be deleted')
    })

    it('is an array of errors', function(){
      phil.errors['attribute_name'].should.be.an.instanceOf(Array)
      phil.errors['attribute_name'][0].should.be.equal('not valid')
    })

    it('has base errors', function(){
      phil.errors['base'].should.be.an.instanceOf(Array)
      phil.errors['base'][0].should.be.equal('can not be deleted')
    })

    it('throws an error on reserved word (add)', function(){
      (function(){
        phil.errors.add('add', 'msg')
      }).should.throw()
    })

    it('throws an error on reserved word (set)', function(){
      (function(){
        phil.errors.add('set', 'msg')
      }).should.throw()
    })

    it('throws an error on reserved word (each)', function(){
      (function(){
        phil.errors.add('each', 'msg')
      }).should.throw()
    })

    it('throws an error on reserved word (toJSON)', function(){
      (function(){
        phil.errors.add('toJSON', 'msg')
      }).should.throw()
    })
  })

  describe('errors.set()', function(){
    it('set multiple attributes', function(){
      phil.errors.set({
        a: 'Error a',
        b: 'Error b'
      })
      phil.errors.a.should.be.eql(['Error a'])
      phil.errors.b.should.be.eql(['Error b'])
    })
  })

  describe('errors.each()', function(){
    it('add attribute error', function(){
      const tmp = []
      phil.errors.each(function(field, error){
        tmp.push(field)
        tmp.push(error)
      })
      tmp.should.be.eql([
        'attribute_name',
        'not valid',
        'base',
        'can not be deleted',
        'a',
        'Error a',
        'b',
        'Error b'
      ])
    })
  })

  describe('errors.toJSON()', function(){
    it('returns the json representation', function(){
      phil.errors.toJSON().should.be.eql({
        attribute_name: [ 'not valid' ],
        a: ['Error a'],
        base: ['can not be deleted'],
        b: ['Error b']
      })
    })
  })

  describe('errors.toString()', function(){
    it('set converts all errors to a string', function(){
      phil.errors.toString().should.be.equal('attribute_name: not valid\ncan not be deleted\na: Error a\nb: Error b')
    })
  })

  describe('relation errors', function(){
    before(function(){
      michl.posts[0].errors.add('title', 'some title error')
      michl.avatar.errors.add('url', 'some url error')
    })

    it('has the posts error object on its error obj.', function(){
      michl.errors.should.have.property('posts')
    })

    it('has the avatar error object on its error obj.', function(){
      michl.errors.should.have.property('avatar')
    })

    it('errors is an array for hasMany', function(){
      michl.errors.posts.should.be.instanceOf(Array)
    })

    it('errors is an object for belongsTo', function(){
      michl.errors.avatar.should.not.be.instanceOf(Array)
    })
  })
})
<|endoftext|>


<commit_before>/*ConnextCMS pluginView.js - This file loads plugins at run-time.*/
define([
	'jQuery-2.1.4.min',
	'underscore_1.3.3',
	'backbone_0.9.2',
  'text!../../../js/app/templates/pluginTemplate.html'
], function ($, _, Backbone, PluginTemplate) {
	'use strict';

	var PostsView = Backbone.View.extend({

		tagName:  'div',

    el: '#pluginDiv',

		template: _.template(PluginTemplate),

		// The DOM events specific to an item.
		events: {

		},

		initialize: function () {
      this.loadedPlugins = []; //An array containing all the loaded plugins and their Backbone constructs.
      this.pluginData = []; //An array containing the contents of the pluginSettings.json file (the metadata) for each plugin.
		},

    render: function () {
      //debugger;

      var thisView = this;

      this.$el.html(this.template);

      $.get('/api/plugins/list', '', function(data) {
        //debugger;

        //Error Handling
        if( (!data.success) || (data.plugins.length == 0) ) {
          return;
        }

        //Save the pluginSettings.json data
        thisView.pluginData = data.plugins; //Copy the plugin data (for all plugins) to the Plugin View
        var pluginData = data.plugins;      //Also copy the plugin data to a local variable.

        //Loop through each PLUGIN
        for(var i=0; i < pluginData.length; i++) {

          //Add a div to the DOM. This will be the div for the current plugin.
          thisView.$el.find('#pluginParentDiv').append('

');

          //Tell the plugin which div belongs to it.
          thisView.pluginData[i].divId = '#plugin'+i;
          thisView.pluginData[i].pluginIndex = i;

          //Prep the loadedPlugins object for this plugin with an empty object.
          var tmpObj = {};
          tmpObj.views = [];
          tmpObj.models = [];
          tmpObj.collections = [];
          thisView.loadedPlugins[i] = tmpObj;

          //Load the Backbone Views, Models, and Collections associated with this plugin.
          thisView.loadViews(i);

          //Load the Backbone Models
          thisView.loadModels(i);
        }

      });

			return this;
		},

    //This function instantiates the Backbone Views, Models, and Collections associated with a plugin.
    //It expects the plugin metadata to be passed into it. This is the data stored in the pluginSettings.json
    loadViews: function(pluginIndex) {
      //debugger;

      //Get local handles to view-level objects.
      var thisView = this;                                //Get a handle on this View.
      var thisPluginData = this.pluginData[pluginIndex];  //Plugin Metadata
      var thisPlugin = this.loadedPlugins[pluginIndex];   //Will hold the plugins Backbone constructs.

      // ---BEGIN BACKBONE VIEWS---

      //Loop through each of the backbone views for this plugin.
      //Have to use an async for loop since we making async calls to $.getScript().
      global.async.eachOf(thisPluginData.backboneViewFiles, function(value, key, callback) {
        //debugger;

        try {

          var pluginDir = '/plugins/'+thisPluginData.pluginDirName+'/';

          //Load the individual views for this plugin. Generate a promise for each view.
          var scriptPromise = $.getScript(pluginDir+value, function(data, textStatus, jqxhr) {
            //debugger;

          })
          .fail(function( jqxhr, settings, exception ) {
            debugger;

            console.error('Problem with pluginView.js/loadViews() when trying load Backbone Views: '+exception);
          });

          //When the promise resolves:
          scriptPromise.then(function(results) {
            //debugger;

            //Scope is lost at the point and a handle needs to be established on the current plugin.
            var thisPluginIndex = global.pluginView.getPluginIndex('backboneViewNames', results);
            if(thisPluginIndex == null) {
              var msg = 'Could not find plugin.';
              console.error(msg);
              callback(msg);
              return;
            } else {
              var thisPluginData = global.pluginView.pluginData[thisPluginIndex];
              var thisPlugin = global.pluginView.loadedPlugins[thisPluginIndex];
            }

            //Create the new view.
            var constructor = "new "+thisPluginData.backboneViewNames[key]+"({el: $(thisPluginData.divId), pluginData: thisPluginData, pluginHandle: thisPlugin })";
            var thisView = eval(constructor);

            //Add this view to the loadedPlugins.views[] array.
            thisPlugin.views.push(thisView);

            //Create a global reference to the primary view that should be loaded when the user
            //clicks on the left menu entry for this plugin.
            if(thisPluginData.primaryViewConstructor == thisPluginData.backboneViewNames[key]) {

              var pluginViewReference = "global.pluginView."+thisPluginData.primaryViewInstance;
              var evalStr = pluginViewReference+" = thisPlugin.views["+key+"]";
              eval(evalStr);

              //Add a menu item for this primary view.
              var tmpLi = '
 '+thisPluginData.primaryViewLabel+'
';
              var pluginLi = global.leftMenuView.$el.find('#plugin-link');
              pluginLi.parent().append(tmpLi);
            }

            //debugger;
            //loadModels();
            //callback();

          }, function(error) {
            debugger;
            callback(error);
          });

        } catch(err) {
          callback(err);
        }

      }, function(err) {
        debugger;

        if(err) {
          debugger;
          console.error('Problem with pluginView.js/loadViews() when trying to load Backbone Views: '+err);
        } else {
          debugger;

          //Views have been loaded. Next, load the models.
          //global.pluginView.loadModels();
        }

      });
      // ---END BACKBONE VIEWS---

    },

    // ---BEGIN BACKBONE MODELS---

    //This function is called in parallel with loadViews(). It's purpose is to load the
    //Backbone models associated with this plugin.
    loadModels: function(pluginIndex) {
      //debugger;

      //Get local handles to view-level objects.
      var thisView = this;                                //Get a handle on this View.
      var thisPluginData = this.pluginData[pluginIndex];  //Plugin Metadata
      var thisPlugin = this.loadedPlugins[pluginIndex];   //Will hold the plugins Backbone constructs.

      //Loop through each of the backbone views for this plugin.
      //Have to use an async for loop since we making async calls to $.getScript().
      global.async.eachOf(thisPluginData.backboneModelFiles, function(value, key, callback) {
        try {

          var pluginDir = '/plugins/'+thisPluginData.pluginDirName+'/';

          //Load the individual views for this plugin. Generate a promise for each view.
          var scriptPromise = $.getScript(pluginDir+value, function(data, textStatus, jqxhr) {

          })
          .fail(function( jqxhr, settings, exception ) {
            debugger;

            console.error('Problem with pluginView.js/loadModels() when trying load Backbone Models: '+exception);
            callback(exception);
          });

          //When the promise resolves:
          scriptPromise.then(function(results) {
            debugger;

            //Scope is lost at the point and a handle needs to be established on the current plugin.
            var thisPluginIndex = global.pluginView.getPluginIndex('backboneModelNames', results);
            if(thisPluginIndex == null) {
              var msg = 'Could not find plugin.';
              console.error(msg);
              callback(msg);
              return;
            } else {
              var thisPluginData = global.pluginView.pluginData[thisPluginIndex];
              var thisPlugin = global.pluginView.loadedPlugins[thisPluginIndex];
            }

            var constructor = "new "+thisPluginData.backboneModelNames[key]+"(null,{pluginData: thisPluginData, pluginHandle: thisPlugin })";
            var thisModel = eval(constructor);

            thisPlugin.models.push(thisModel);

            //If this is the last model in the plugin, I can safely load the Collections
            //associated with this plugin.
            if(key == thisPluginData.backboneModelFiles.length-1) {
              global.pluginView.loadCollections(thisPluginData.pluginIndex);
            }

          }, function(err) {
            debugger;
            callback(err);
          });

        } catch(err) {
          callback(err);
        }

      }, function(err) {
        debugger;

        if(err) {
          debugger;
          console.error('Problem with pluginView.js/loadModels() when trying to load Backbone Models: '+err);
        } else {
          debugger;

          //Views have been loaded. Next, load the models.
          //global.pluginView.loadModels();
        }

      });
    },

    //This function is called AFTER loadModels() have loaded all the models associated with a plugin.
    //The purpose of this function is to load the Backbone Collections associated with this plugin.
    //Since Collections usually DEPEND on models, it's important to load them after the Models have
    //been instantiated.
    loadCollections: function(pluginIndex) {
      //debugger;

      //Get local handles to view-level objects.
      var thisView = this;                                //Get a handle on this View.
      var thisPluginData = this.pluginData[pluginIndex];  //Plugin Metadata
      var thisPlugin = this.loadedPlugins[pluginIndex];   //Will hold the plugins Backbone constructs.

      //Loop through each of the backbone views for this plugin.
      //Have to use an async for loop since we making async calls to $.getScript().
      global.async.eachOf(thisPluginData.backboneCollectionFiles, function(value, key, callback) {
        try {

          var pluginDir = '/plugins/'+thisPluginData.pluginDirName+'/';

          //Load the individual Collections for this plugin. Generate a promise for each Collection.
          var scriptPromise = $.getScript(pluginDir+value, function(data, textStatus, jqxhr) {

          })
          .fail(function( jqxhr, settings, exception ) {
            debugger;

            console.error('Problem with pluginView.js/loadCollections() when trying load Backbone Collections: '+exception);
            callback(exception);
          });

          //When the promise resolves:
          scriptPromise.then(function(results) {
            debugger;

            //Scope is lost at this point and a handle needs to be established on the current plugin.
            var thisPluginIndex = global.pluginView.getPluginIndex('backboneCollectionNames', results);
            if(thisPluginIndex == null) {
              var msg = 'Could not find plugin.';
              console.error(msg);
              callback(msg);
              return;
            } else {
              var thisPluginData = global.pluginView.pluginData[thisPluginIndex];
              var thisPlugin = global.pluginView.loadedPlugins[thisPluginIndex];
            }

            var constructor = "new "+thisPluginData.backboneCollectionNames[key]+"({pluginData: pluginData, pluginHandle: thisPlugin })";
            var thisCollection = eval(constructor);

            thisPlugin.collections.push(thisCollection);

          }, function(err) {
            debugger;
            callback(err);
          });

        } catch(err) {
          callback(err);
        }

      }, function(err) {
        debugger;

        if(err) {
          debugger;
          console.error('Problem with pluginView.js/loadCollectionss() when trying to load Backbone Collections: '+err);
        } else {
          debugger;

          //Views have been loaded. Next, load the models.
          //global.pluginView.loadModels();
        }

      });
    },

    // ---END BACKBONE MODELS---

    // ---BEGIN UTILITY FUNCTIONS---

    //Dev note: I don't think this function is used any more.
    //This function returns a pointer to the global.pluginView.loadedPlugins[] element
    //that matches the directory name stored in that plugins metadata. It's useful for
    //getting the plugin constructs in a function without any scope.
    //If the loaded plugin can not be found, then this functioin returns false.
    getHandle: function(dirName) {
      try {
        debugger;

        for(var i=0; i < global.pluginView.pluginData.length; i++) {
          if(dirName == global.pluginView.pluginData[i].pluginDirName) {
            return global.pluginView.loadedPlugins[i];
          }
        }

        return false;

      } catch(err) {
          console.error('Problem in pluginView.js/getHandle(): '+err);
      }
    },

    //This function is used to retrieve the plugin index -e.g. which plugin inside
    //global.pluginView.pluginData that we're trying to deal with. It returns
    //the element inside the global.pluginView.pluginData array that matches the
    //key and script. If no match is found, it returns null.
    //This function is used to regain scope on the currently targeted plugin.
    //
    //Since this function uses text matching, it can cause a false positive when
    //text in the Backbone files are copied from the template. If this because
    //a serious issue, I might want to think of ways to refine this function.
    getPluginIndex: function(key, script) {
      //debugger;

      try {
        var thisPluginIndex = null;

        //Loop through each plugin's metadata.
        for(var i=0; i < global.pluginView.pluginData.length; i++) {

          //Loop through each element in the key field.
          var keyArray = eval('global.pluginView.pluginData[i].'+key);

          for(var j=0; j < keyArray.length; j++) {
            if(script.indexOf(keyArray[j]) > -1) {
              console.log('pluginView.js/getPluginIndex() found a match with '+keyArray[j]);
              thisPluginIndex = i;
              return thisPluginIndex;
            }
          }
        }

        if(thisPluginIndex == null) {
          debugger;
          console.error('Problem in pluginView.js/getPluginIndex(). Could not identify the view and could not find the plugin index. key = '+key);
          return null;
        }

      } catch(err) {
        debugger;
        console.log('Error in getPluginIndex(): '+err);
        return null;
      }
    }

    // ---END UTILITY FUNCTIONS---

	});

  //debugger;
	return PostsView;
});<commit_msg>Importing pluginLoader.js code into pluginView.js<commit_after>/*ConnextCMS pluginView.js - This file loads plugins at run-time.*/
define([
	'jQuery-2.1.4.min',
	'underscore_1.3.3',
	'backbone_0.9.2',
  'text!../../../js/app/templates/pluginTemplate.html'
], function ($, _, Backbone, PluginTemplate) {
	'use strict';

	var PostsView = Backbone.View.extend({

		tagName:  'div',

    el: '#pluginDiv',

		template: _.template(PluginTemplate),

		// The DOM events specific to an item.
		events: {

		},

		initialize: function () {
      this.loadedPlugins = []; //An array containing all the loaded plugins and their Backbone constructs.
      this.pluginData = []; //An array containing the contents of the pluginSettings.json file (the metadata) for each plugin.
		},

    render: function () {
      //debugger;

      var thisView = this;

      this.$el.html(this.template);

      $.get('/api/plugins/list', '', function(data) {
        //debugger;

        //Error Handling
        if( (!data.success) || (data.plugins.length == 0) ) {
          return;
        }

        //Save the pluginSettings.json data
        thisView.pluginData = data.plugins; //Copy the plugin data (for all plugins) to the Plugin View
        var pluginData = data.plugins;      //Also copy the plugin data to a local variable.

        //Loop through each PLUGIN
        for(var i=0; i < pluginData.length; i++) {

          //Add a div to the DOM. This will be the div for the current plugin.
          thisView.$el.find('#pluginParentDiv').append('

');

          //Tell the plugin which div belongs to it.
          thisView.pluginData[i].divId = '#plugin'+i;
          thisView.pluginData[i].pluginIndex = i;

          //Prep the loadedPlugins object for this plugin with an empty object.
          var tmpObj = {};
          tmpObj.views = [];
          tmpObj.models = [];
          tmpObj.collections = [];
          thisView.loadedPlugins[i] = tmpObj;

          //Load the Backbone Views, Models, and Collections associated with this plugin.
          thisView.loadViews(i);

          //Load the Backbone Models
          thisView.loadModels(i);
        }

      });

			return this;
		},

    //This function instantiates the Backbone Views, Models, and Collections associated with a plugin.
    //It expects the plugin metadata to be passed into it. This is the data stored in the pluginSettings.json
    loadViews: function(pluginIndex) {
      //debugger;

      //Get local handles to view-level objects.
      var thisView = this;                                //Get a handle on this View.
      var thisPluginData = this.pluginData[pluginIndex];  //Plugin Metadata
      var thisPlugin = this.loadedPlugins[pluginIndex];   //Will hold the plugins Backbone constructs.

      // ---BEGIN BACKBONE VIEWS---

      //Loop through each of the backbone views for this plugin.
      //Have to use an async for loop since we making async calls to $.getScript().
      global.async.eachOf(thisPluginData.backboneViewFiles, function(value, key, callback) {
        //debugger;

        try {

          var pluginDir = '/plugins/'+thisPluginData.pluginDirName+'/';

          //Load the individual views for this plugin. Generate a promise for each view.
          var scriptPromise = $.getScript(pluginDir+value, function(data, textStatus, jqxhr) {
            //debugger;

          })
          .fail(function( jqxhr, settings, exception ) {
            debugger;

            console.error('Problem with pluginView.js/loadViews() when trying load Backbone Views: '+exception);
          });

          //When the promise resolves:
          scriptPromise.then(function(results) {
            //debugger;

            //Scope is lost at the point and a handle needs to be established on the current plugin.
            var thisPluginIndex = global.pluginView.getPluginIndex('backboneViewNames', results);
            if(thisPluginIndex == null) {
              var msg = 'Could not find plugin.';
              console.error(msg);
              callback(msg);
              return;
            } else {
              var thisPluginData = global.pluginView.pluginData[thisPluginIndex];
              var thisPlugin = global.pluginView.loadedPlugins[thisPluginIndex];
            }

            //Create the new view.
            var constructor = "new "+thisPluginData.backboneViewNames[key]+"({el: $(thisPluginData.divId), pluginData: thisPluginData, pluginHandle: thisPlugin })";
            var thisView = eval(constructor);

            //Add this view to the loadedPlugins.views[] array.
            thisPlugin.views.push(thisView);

            //Create a global reference to the primary view that should be loaded when the user
            //clicks on the left menu entry for this plugin.
            if(thisPluginData.primaryViewConstructor == thisPluginData.backboneViewNames[key]) {

              var pluginViewReference = "global.pluginView."+thisPluginData.primaryViewInstance;
              var evalStr = pluginViewReference+" = thisPlugin.views["+key+"]";
              eval(evalStr);

              //Add a menu item for this primary view.
              var tmpLi = '
 '+thisPluginData.primaryViewLabel+'
';
              var pluginLi = global.leftMenuView.$el.find('#plugin-link');
              pluginLi.parent().append(tmpLi);
            }

            //debugger;
            //loadModels();
            //callback();

          }, function(error) {
            debugger;
            callback(error);
          });

        } catch(err) {
          callback(err);
        }

      }, function(err) {
        debugger;

        if(err) {
          debugger;
          console.error('Problem with pluginView.js/loadViews() when trying to load Backbone Views: '+err);
        } else {
          debugger;

          //Views have been loaded. Next, load the models.
          //global.pluginView.loadModels();
        }

      });
      // ---END BACKBONE VIEWS---

    },

    // ---BEGIN BACKBONE MODELS---

    //This function is called in parallel with loadViews(). It's purpose is to load the
    //Backbone models associated with this plugin.
    loadModels: function(pluginIndex) {
      //debugger;

      //Get local handles to view-level objects.
      var thisView = this;                                //Get a handle on this View.
      var thisPluginData = this.pluginData[pluginIndex];  //Plugin Metadata
      var thisPlugin = this.loadedPlugins[pluginIndex];   //Will hold the plugins Backbone constructs.

      //Loop through each of the backbone views for this plugin.
      //Have to use an async for loop since we making async calls to $.getScript().
      global.async.eachOf(thisPluginData.backboneModelFiles, function(value, key, callback) {
        try {

          var pluginDir = '/plugins/'+thisPluginData.pluginDirName+'/';

          //Load the individual views for this plugin. Generate a promise for each view.
          var scriptPromise = $.getScript(pluginDir+value, function(data, textStatus, jqxhr) {

          })
          .fail(function( jqxhr, settings, exception ) {
            debugger;

            console.error('Problem with pluginView.js/loadModels() when trying load Backbone Models: '+exception);
            callback(exception);
          });

          //When the promise resolves:
          scriptPromise.then(function(results) {
            //debugger;

            //Scope is lost at the point and a handle needs to be established on the current plugin.
            var thisPluginIndex = global.pluginView.getPluginIndex('backboneModelNames', results);
            if(thisPluginIndex == null) {
              var msg = 'Could not find plugin.';
              console.error(msg);
              callback(msg);
              return;
            } else {
              var thisPluginData = global.pluginView.pluginData[thisPluginIndex];
              var thisPlugin = global.pluginView.loadedPlugins[thisPluginIndex];
            }

            var constructor = "new "+thisPluginData.backboneModelNames[key]+"(null,{pluginData: thisPluginData, pluginHandle: thisPlugin })";
            var thisModel = eval(constructor);

            thisPlugin.models.push(thisModel);

            //If this is the last model in the plugin, I can safely load the Collections
            //associated with this plugin.
            if(key == thisPluginData.backboneModelFiles.length-1) {
              global.pluginView.loadCollections(thisPluginData.pluginIndex);
            }

          }, function(err) {
            debugger;
            callback(err);
          });

        } catch(err) {
          callback(err);
        }

      }, function(err) {
        debugger;

        if(err) {
          debugger;
          console.error('Problem with pluginView.js/loadModels() when trying to load Backbone Models: '+err);
        } else {
          debugger;

          //Views have been loaded. Next, load the models.
          //global.pluginView.loadModels();
        }

      });
    },

    //This function is called AFTER loadModels() have loaded all the models associated with a plugin.
    //The purpose of this function is to load the Backbone Collections associated with this plugin.
    //Since Collections usually DEPEND on models, it's important to load them after the Models have
    //been instantiated.
    loadCollections: function(pluginIndex) {
      //debugger;

      //Get local handles to view-level objects.
      var thisView = this;                                //Get a handle on this View.
      var thisPluginData = this.pluginData[pluginIndex];  //Plugin Metadata
      var thisPlugin = this.loadedPlugins[pluginIndex];   //Will hold the plugins Backbone constructs.

      //Loop through each of the backbone views for this plugin.
      //Have to use an async for loop since we making async calls to $.getScript().
      global.async.eachOf(thisPluginData.backboneCollectionFiles, function(value, key, callback) {
        try {

          var pluginDir = '/plugins/'+thisPluginData.pluginDirName+'/';

          //Load the individual Collections for this plugin. Generate a promise for each Collection.
          var scriptPromise = $.getScript(pluginDir+value, function(data, textStatus, jqxhr) {

          })
          .fail(function( jqxhr, settings, exception ) {
            debugger;

            console.error('Problem with pluginView.js/loadCollections() when trying load Backbone Collections: '+exception);
            callback(exception);
          });

          //When the promise resolves:
          scriptPromise.then(function(results) {
            //debugger;

            //Scope is lost at this point and a handle needs to be established on the current plugin.
            var thisPluginIndex = global.pluginView.getPluginIndex('backboneCollectionNames', results);
            if(thisPluginIndex == null) {
              var msg = 'Could not find plugin.';
              console.error(msg);
              callback(msg);
              return;
            } else {
              var thisPluginData = global.pluginView.pluginData[thisPluginIndex];
              var thisPlugin = global.pluginView.loadedPlugins[thisPluginIndex];
            }

            var constructor = "new "+thisPluginData.backboneCollectionNames[key]+"({pluginData: pluginData, pluginHandle: thisPlugin })";
            var thisCollection = eval(constructor);

            thisPlugin.collections.push(thisCollection);

          }, function(err) {
            debugger;
            callback(err);
          });

        } catch(err) {
          callback(err);
        }

      }, function(err) {
        debugger;

        if(err) {
          debugger;
          console.error('Problem with pluginView.js/loadCollectionss() when trying to load Backbone Collections: '+err);
        } else {
          debugger;

          //Views have been loaded. Next, load the models.
          //global.pluginView.loadModels();
        }

      });
    },

    // ---END BACKBONE MODELS---

    // ---BEGIN UTILITY FUNCTIONS---

    //Dev note: I don't think this function is used any more.
    //This function returns a pointer to the global.pluginView.loadedPlugins[] element
    //that matches the directory name stored in that plugins metadata. It's useful for
    //getting the plugin constructs in a function without any scope.
    //If the loaded plugin can not be found, then this functioin returns false.
    getHandle: function(dirName) {
      try {
        debugger;

        for(var i=0; i < global.pluginView.pluginData.length; i++) {
          if(dirName == global.pluginView.pluginData[i].pluginDirName) {
            return global.pluginView.loadedPlugins[i];
          }
        }

        return false;

      } catch(err) {
          console.error('Problem in pluginView.js/getHandle(): '+err);
      }
    },

    //This function is used to retrieve the plugin index -e.g. which plugin inside
    //global.pluginView.pluginData that we're trying to deal with. It returns
    //the element inside the global.pluginView.pluginData array that matches the
    //key and script. If no match is found, it returns null.
    //This function is used to regain scope on the currently targeted plugin.
    //
    //Since this function uses text matching, it can cause a false positive when
    //text in the Backbone files are copied from the template. If this because
    //a serious issue, I might want to think of ways to refine this function.
    getPluginIndex: function(key, script) {
      //debugger;

      try {
        var thisPluginIndex = null;

        //Loop through each plugin's metadata.
        for(var i=0; i < global.pluginView.pluginData.length; i++) {

          //Loop through each element in the key field.
          var keyArray = eval('global.pluginView.pluginData[i].'+key);

          for(var j=0; j < keyArray.length; j++) {
            if(script.indexOf(keyArray[j]) > -1) {
              console.log('pluginView.js/getPluginIndex() found a match with '+keyArray[j]);
              thisPluginIndex = i;
              return thisPluginIndex;
            }
          }
        }

        if(thisPluginIndex == null) {
          debugger;
          console.error('Problem in pluginView.js/getPluginIndex(). Could not identify the view and could not find the plugin index. key = '+key);
          return null;
        }

      } catch(err) {
        debugger;
        console.log('Error in getPluginIndex(): '+err);
        return null;
      }
    }

    // ---END UTILITY FUNCTIONS---

	});

  //debugger;
	return PostsView;
});<|endoftext|>


<commit_before>angular.module('starter.services', [])

.factory('Chats', function() {
  // Might use a resource here that returns a JSON array

  // Some fake testing data
  var chats = [{
    id: 0,
    name: 'Ben Sparrow',
    lastText: 'You on your way?',
    face: 'img/ben.png'
  }, {
    id: 1,
    name: 'Max Lynx',
    lastText: 'Hey, it\'s me',
    face: 'img/max.png'
  }, {
    id: 2,
    name: 'Adam Bradleyson',
    lastText: 'I should buy a boat',
    face: 'img/adam.jpg'
  }, {
    id: 3,
    name: 'Perry Governor',
    lastText: 'Look at my mukluks!',
    face: 'img/perry.png'
  }, {
    id: 4,
    name: 'Mike Harrington',
    lastText: 'This is wicked good ice cream.',
    face: 'img/mike.png'
  }];

  return {
    all: function() {
      return chats;
    },
    remove: function(chat) {
      chats.splice(chats.indexOf(chat), 1);
    },
    get: function(chatId) {
      for (var i = 0; i < chats.length; i++) {
        if (chats[i].id === parseInt(chatId)) {
          return chats[i];
        }
      }
      return null;
    }
  };
})

.factory('Flights', function($http){

  return {
    all: function() {
      // get all the flights ????
      return $http({
        method: 'GET',
        url: '/someUrl'
      });
    },
    from: function(departureLocation, arrivalLocation, date) {
      //returns all the flights leaving from a specific location, to a given location, arriving on a certain date
      return;
    }
  };
})
<commit_msg>Fixed passing  provider to the flight service<commit_after>angular.module('starter.services', [])

.factory('Chats', function() {
  // Might use a resource here that returns a JSON array

  // Some fake testing data
  var chats = [{
    id: 0,
    name: 'Ben Sparrow',
    lastText: 'You on your way?',
    face: 'img/ben.png'
  }, {
    id: 1,
    name: 'Max Lynx',
    lastText: 'Hey, it\'s me',
    face: 'img/max.png'
  }, {
    id: 2,
    name: 'Adam Bradleyson',
    lastText: 'I should buy a boat',
    face: 'img/adam.jpg'
  }, {
    id: 3,
    name: 'Perry Governor',
    lastText: 'Look at my mukluks!',
    face: 'img/perry.png'
  }, {
    id: 4,
    name: 'Mike Harrington',
    lastText: 'This is wicked good ice cream.',
    face: 'img/mike.png'
  }];

  return {
    all: function() {
      return chats;
    },
    remove: function(chat) {
      chats.splice(chats.indexOf(chat), 1);
    },
    get: function(chatId) {
      for (var i = 0; i < chats.length; i++) {
        if (chats[i].id === parseInt(chatId)) {
          return chats[i];
        }
      }
      return null;
    }
  };
})

.factory('Flights', ['$http', function($http){

  return {
    all: function() {
      // get all the flights ????
      return $http({
        method: 'GET',
        url: '/someUrl'
      });
    },
    from: function(departureLocation, arrivalLocation, date) {
      //returns all the flights leaving from a specific location, to a given location, arriving on a certain date
      return;
    }
  };
}]);
<|endoftext|>


<commit_before>Box.Application.addService('post', (application) => {
  'use strict'

  let $ = application.getGlobal('jQuery')

  return {
    getAllPost: function () {
      return new Promise((resolve, reject) => {
        $.ajax({
          url: '/api/posts',
          type: 'get',
          dataType: 'json',
          success: (data) => resolve(data),
          error: (err) => reject(err)
        })
      })
    },

    getPostById: function (id) {
      return new Promise((resolve, reject) => {
        $.ajax({
          url: '/api/posts/' + id,
          type: 'get',
          dataType: 'json',
          success: (data) => resolve(data),
          error: (err) => reject(err)
        })
      })
    },

    savePost: function (post) {
      return new Promise((resolve, reject) => {
        $.ajax({
          url: '/api/posts',
          type: 'post',
          data: post,
          dataType: 'json',
          success: (data) => resolve(data),
          error: (err) => reject(err)
        })
      })
    },

    updatePost: function (post) {
      return new Promise((resolve, reject) => {
        $.ajax({
          url: '/api/posts/' + post.id,
          type: 'put',
          data: post,
          dataType: 'json',
          success: (data) => resolve(data),
          error: (err) => reject(err)
        })
      })
    }
  }
})
<commit_msg>Add deletePost function<commit_after>Box.Application.addService('post', (application) => {
  'use strict'

  let $ = application.getGlobal('jQuery')

  return {
    getAllPost: function () {
      return new Promise((resolve, reject) => {
        $.ajax({
          url: '/api/posts',
          type: 'get',
          dataType: 'json',
          success: (data) => resolve(data),
          error: (err) => reject(err)
        })
      })
    },

    getPostById: function (id) {
      return new Promise((resolve, reject) => {
        $.ajax({
          url: '/api/posts/' + id,
          type: 'get',
          dataType: 'json',
          success: (data) => resolve(data),
          error: (err) => reject(err)
        })
      })
    },

    savePost: function (post) {
      return new Promise((resolve, reject) => {
        $.ajax({
          url: '/api/posts',
          type: 'post',
          data: post,
          dataType: 'json',
          success: (data) => resolve(data),
          error: (err) => reject(err)
        })
      })
    },

    updatePost: function (post) {
      return new Promise((resolve, reject) => {
        $.ajax({
          url: '/api/posts/' + post.id,
          type: 'put',
          data: post,
          dataType: 'json',
          success: (data) => resolve(data),
          error: (err) => reject(err)
        })
      })
    },

    deletePost: function(id) {
      return new Promise((resolve, reject) => {
        $.ajax({
          url: '/api/posts/' + post.id,
          type: 'delete',
          data: id,
          dataType: 'json',
          success: (data) => resolve(data),
          error: (err) => reject(err)
        })
      })
    }
  }
})
<|endoftext|>


<commit_before>'use strict';

import glob from 'glob';
import mongoose from 'mongoose';

/**
 * Konko server utilities.
 *
 * @author C Killua
 * @module Konko/Server/Configurations/Utilities
 */
export default class Utilities {

  /**
   * @constructs
   */
  constructor() {}

  /**
   * Helper to record X-Rate-Limit-* in production mode.
   *
   * @param {Object} req - HTTP request.
   * @param {Object} res - HTTP response.
   * @param {nextCallback} next - A callback to run.
   * @returns {nextCallback} Call next middleware.
   */
  static throttle(req, res, next) {
    if (process.env.NODE_ENV !== 'production') {
      return next();
    }

    const RateLimit = mongoose.model('RateLimit');
    let ip = req.headers['x-forwarded-for'] ||
             req.connection.remoteAddress ||
             req.socket.remoteAddress ||
             req.connection.socket.remoteAddress;
    console.log(req.ip, req.ips);
    console.log(req.connection.remoteAddress);
    console.log(ip);
    RateLimit.findOneAndUpdate({ ip: ip }, { $inc: { hits: 1 } }, { upsert: false })
      .exec().then(rateLimit => {
        if (!rateLimit) {
          RateLimit.create({ ip: ip }).then(rateLimit => {
            let reset = 10 * 60 * 1000 - (new Date().getTime() - rateLimit.expiresAt.getTime());
            res.set('X-Rate-Limit-Limit', 600);
            res.set('X-Rate-Limit-Remaining', 600 - rateLimit.hits);
            res.set('X-Rate-Limit-Reset', reset);
            req.rateLimit = rateLimit;
            return next();
          }).catch(err => {
            res.statusCode = 500;
            return next(err);
          });
        } else {
          let reset = 10 * 60 * 1000 - (new Date().getTime() - rateLimit.expiresAt.getTime());
          res.set('X-Rate-Limit-Limit', 600);
          res.set('X-Rate-Limit-Remaining', 600 - rateLimit.hits);
          res.set('X-Rate-Limit-Reset', reset);
          req.rateLimit = rateLimit;
          if (rateLimit.hits > 600) {
            return res.status(429).json({ message: 'Too Many Requests' });
          } else {
            return next();
          }
        }
      }).catch(err => {
        res.statusCode = 500;
        return next(err);
      });
  }

  /**
   * Helper to process quering string
   *
   * @param {Object} req - HTTP request.
   * @param {Object} res - HTTP response.
   * @param {nextCallback} next - A callback to run.
   * @returns {nextCallback} Call next middleware.
   */
  static quering(req, res, next) {
    req._fields = '';
    req._sort = {};
    if (req.query && req.query.sort) {
      for (let s of req.query.sort) {
        if (s.charAt(0) === '-') {
          req._sort[s.substr(1)] = -1;
        } else {
          req._sort[s] = 1;
        }
      }
    }
    if (req.query && req.query.fields) {
      req._fields = req.query.fields.replace(',', ' ');
    }
    return next();
  }

  /**
   * Validate a cookie secret if a default one, custom one, or null
   *
   * @param {String} secret - Cookie secret.
   * @param {Boolean} log - Indicates should log to console or not.
   * @returns {Boolean} true if cookie is valid, false otherwise.
   */
  static validCookieSecret(secret, log) {
    if (process.env.NODE_ENV !== 'production') {
      return true;
    } else if (secret === 'DEFAULTCOOKIE') {
      if (log) {
        console.log('* Default cookie secret is in used!');
        console.log('* It\'s recommended to modify your default cookie secret before running Konko in production mode.');
        console.log('* You can modify the cookie secret in configuration/secrets.js in the root directory of Konko.');
      }

      return false;
    } else if (!secret) {
      if (log) {
        console.log('* Cookie secret is empty or undefined!');
        console.log('* It\'s recommended to use cookie secret to run Konko in production mode.');
        console.log('* You can set cookie secret in configuration/secrets.js in the root directory of Konko using node module exports.');
        console.log('  - Please use \'cookieSecret\' as key.');
        console.log('  - Please refer to other configurations for constructing a node module.');
        console.log('  - Please set cookie secret to be something other than \'DEFAULTCOOKIE\'');
      }

      return false;
    } else {
      return true;
    }
  }

  /**
   * Validate a jwt secret if a default one, custom one, or null
   *
   * @param {String} secret - JWT secret.
   * @param {Boolean} log - Indicates should log to console or not.
   * @returns {Boolean} true if cookie is valid, false otherwise.
   */
  static validJwtSecret(secret, log) {
    if (process.env.NODE_ENV !== 'production') {
      return true;
    } else if (secret === 'DEFAULTJWT') {
      if (log) {
        console.log('* Default jwt secret is in used!');
        console.log('* It\'s recommended to modify your default JWT secret before running Konko in production mode.');
        console.log('* You can modify the cookie secret in configuration/secrets.js in the root directory of Konko.');
      }

      return false;
    } else if (!secret) {
      if (log) {
        console.error('* JWT secret is empty or undefined!');
        console.error('* JWT secret is required for Konko.');
        console.error('* Please set the jwt secret in configuration/secrets.js in the root directory of Konko using node module exports.');
        console.error('  - Please use \'jwtSecret\' as key.');
        console.error('  - Please refer to other configurations for constructing a node module.');
        console.error('  - Please set jwt secret to be something other than \'DEFAULTJWT\'');
      }

      return false;
    } else {
      return true;
    }
  }

  /**
   * Validate if exist a configuration for Express-Mailer.
   *
   * @param {String} path - Path where is the config file located.
   * @param {Boolean} log - Indicates should log to console or not.
   * @returns {Boolean} true if has a config file, false otherwise.
   */
  static hasExpressMailerConfiguration(path, log) {
    if (process.env.NODE_ENV !== 'production') {
      return true;
    }

    glob.sync(path).forEach(file => {
      if (file.match(/mailer/gi)) {
        return true;
      }
    });
    if (log) {
      console.error('! Express-Mailer configuration is missing.');
      console.error('! Konko will be running without any email functionality.');
    }

    return false;
  }

  /**
   * Update an object with new value if has one.
   *
   * @param {Object} data - An object that stores the new values.
   * @param {Object} obj - The original object.
   * @param {Array} props - An array of object properties that need to be updated.
   */
  static partialUpdate(data, obj, ...props) {
    for (let prop of props) {
      if(data.hasOwnProperty(prop)) {
        obj[prop] = data[prop];
      }
    }
  }
}

/**
 * Callback that calls next middleware.
 *
 * @callback nextCallback
 * @param {Object} error - Error, if has any.
 */
<commit_msg>added functions to check publicity and set content language in header<commit_after>'use strict';

import glob from 'glob';
import mongoose from 'mongoose';

/**
 * Konko server utilities.
 *
 * @author C Killua
 * @module Konko/Server/Configurations/Utilities
 */
export default class Utilities {

  /**
   * @constructs
   */
  constructor() {}

  /**
   * Declare content language in header for every response
   *
   * @param {Object} req - HTTP request.
   * @param {Object} res - HTTP response.
   * @param {nextCallback} next - A callback to run.
   * @returns {nextCallback} Call next middleware.
   * @static
   */
  static setLanguage(req, res, next) {
    const Core = mongoose.model('Core');
    Core.findOne().then(core => {
      if (core) {
        res.set('Content-Language', core.global.language);
      } else {
        res.set('Content-Language', 'en-us');
      }
      return next();
    }).catch(err => next(err));
  }

  /**
   * Checks if the site is shut by Admin.
   *
   * @param {Object} req - HTTP request.
   * @param {Object} res - HTTP response.
   * @param {nextCallback} next - A callback to run.
   * @returns {nextCallback} Call next middleware.
   * @static
   */
  static public(req, res, next) {
    if (!req.payload || req.payload.permission === 'admin' || req.url.match('/api/v1/core')) {
      return next();
    }
    const Core = mongoose.model('Core');
    Core.findOne().then(core => {
      if (core && !core.basic.public) {
        return res.status(503).json({ message: 'Site is down.' });
      }
      return next();
    }).catch(err => next(err));
  }

  /**
   * Helper to record X-Rate-Limit-* in production mode.
   *
   * @param {Object} req - HTTP request.
   * @param {Object} res - HTTP response.
   * @param {nextCallback} next - A callback to run.
   * @returns {nextCallback} Call next middleware.
   * @static
   */
  static throttle(req, res, next) {
    if (process.env.NODE_ENV !== 'production') {
      return next();
    }

    const RateLimit = mongoose.model('RateLimit');
    let ip = req.headers['x-forwarded-for'] ||
             req.connection.remoteAddress ||
             req.socket.remoteAddress ||
             req.connection.socket.remoteAddress;
    // console.log(req.ip, req.ips);
    // console.log(req.connection.remoteAddress);
    // console.log(ip);
    RateLimit.findOneAndUpdate({ ip: ip }, { $inc: { hits: 1 } }, { upsert: false })
      .exec().then(rateLimit => {
        if (!rateLimit) {
          RateLimit.create({ ip: ip }).then(rateLimit => {
            let reset = 10 * 60 * 1000 - (new Date().getTime() - rateLimit.expiresAt.getTime());
            res.set('X-Rate-Limit-Limit', 600);
            res.set('X-Rate-Limit-Remaining', 600 - rateLimit.hits);
            res.set('X-Rate-Limit-Reset', reset);
            req.rateLimit = rateLimit;
            return next();
          }).catch(err => {
            res.statusCode = 500;
            return next(err);
          });
        } else {
          let reset = 10 * 60 * 1000 - (new Date().getTime() - rateLimit.expiresAt.getTime());
          res.set('X-Rate-Limit-Limit', 600);
          res.set('X-Rate-Limit-Remaining', 600 - rateLimit.hits);
          res.set('X-Rate-Limit-Reset', reset);
          req.rateLimit = rateLimit;
          if (rateLimit.hits > 600) {
            return res.status(429).json({ message: 'Too Many Requests' });
          } else {
            return next();
          }
        }
      }).catch(err => {
        res.statusCode = 500;
        return next(err);
      });
  }

  /**
   * Helper to process quering string
   *
   * @param {Object} req - HTTP request.
   * @param {Object} res - HTTP response.
   * @param {nextCallback} next - A callback to run.
   * @returns {nextCallback} Call next middleware.
   * @static
   */
  static quering(req, res, next) {
    req._fields = '';
    req._sort = null;
    if (req.query && req.query.sort) {
      req._sort = {};
      for (let s of req.query.sort) {
        if (s.charAt(0) === '-') {
          req._sort[s.substr(1)] = -1;
        } else {
          req._sort[s] = 1;
        }
      }
    }
    if (req.query && req.query.fields) {
      req._fields = req.query.fields.split(',').join(' ');
    }
    return next();
  }

  /**
   * Validate a cookie secret if a default one, custom one, or null
   *
   * @param {String} secret - Cookie secret.
   * @param {Boolean} log - Indicates should log to console or not.
   * @returns {Boolean} true if cookie is valid, false otherwise.
   * @static
   */
  static validCookieSecret(secret, log) {
    if (process.env.NODE_ENV !== 'production') {
      return true;
    } else if (secret === 'DEFAULTCOOKIE') {
      if (log) {
        console.log('* Default cookie secret is in used!');
        console.log('* It\'s recommended to modify your default cookie secret before running Konko in production mode.');
        console.log('* You can modify the cookie secret in configuration/secrets.js in the root directory of Konko.');
      }

      return false;
    } else if (!secret) {
      if (log) {
        console.log('* Cookie secret is empty or undefined!');
        console.log('* It\'s recommended to use cookie secret to run Konko in production mode.');
        console.log('* You can set cookie secret in configuration/secrets.js in the root directory of Konko using node module exports.');
        console.log('  - Please use \'cookieSecret\' as key.');
        console.log('  - Please refer to other configurations for constructing a node module.');
        console.log('  - Please set cookie secret to be something other than \'DEFAULTCOOKIE\'');
      }

      return false;
    } else {
      return true;
    }
  }

  /**
   * Validate a jwt secret if a default one, custom one, or null
   *
   * @param {String} secret - JWT secret.
   * @param {Boolean} log - Indicates should log to console or not.
   * @returns {Boolean} true if cookie is valid, false otherwise.
   * @static
   */
  static validJwtSecret(secret, log) {
    if (process.env.NODE_ENV !== 'production') {
      return true;
    } else if (secret === 'DEFAULTJWT') {
      if (log) {
        console.log('* Default jwt secret is in used!');
        console.log('* It\'s recommended to modify your default JWT secret before running Konko in production mode.');
        console.log('* You can modify the cookie secret in configuration/secrets.js in the root directory of Konko.');
      }

      return false;
    } else if (!secret) {
      if (log) {
        console.error('* JWT secret is empty or undefined!');
        console.error('* JWT secret is required for Konko.');
        console.error('* Please set the jwt secret in configuration/secrets.js in the root directory of Konko using node module exports.');
        console.error('  - Please use \'jwtSecret\' as key.');
        console.error('  - Please refer to other configurations for constructing a node module.');
        console.error('  - Please set jwt secret to be something other than \'DEFAULTJWT\'');
      }

      return false;
    } else {
      return true;
    }
  }

  /**
   * Update an object with new value if has one.
   *
   * @param {Object} data - An object that stores the new values.
   * @param {Object} obj - The original object.
   * @param {Array} props - An array of object properties that need to be updated.
   * @static
   */
  static partialUpdate(data, obj, ...props) {
    for (let prop of props) {
      if(data.hasOwnProperty(prop)) {
        obj[prop] = data[prop];
      }
    }
  }
}

/**
 * Callback that calls next middleware.
 *
 * @callback nextCallback
 * @param {Object} error - Error, if has any.
 */
<|endoftext|>


<commit_before>var app = app || {};

var Keyboard = Backbone.Collection.extend({
  model: app.Key,
});

app.Keyboard = new Keyboard();

app.KeyboardView = Backbone.View.extend({
  el: $('#keyboard'),

  initialize: function() {
    this.listenTo(app.Keyboard, 'reset', this.render);

    app.Keyboard.reset(this.createKeys());
  },

  createKeys: function(){
    var whiteKeyWidth = app.KeyView.whiteKeyWidth;
    var blackKeyWidth = app.KeyView.blackKeyWidth;

    var i = 0, keys = [], octaves = 3;

    for(var index = 0; index < 7 * octaves; index++) {
      i = keys.push(createWhiteKey(index, this.whiteKeyWidth));

      if(hasBlackKey(index)) {
        i = keys.push(createBlackKey(index, this.blackKeyWidth));
      }
    }

    return keys;

    function createWhiteKey(index) {
      return createKey(index * whiteKeyWidth, 'white');
    }

    function createBlackKey(index) {
      return createKey((index + 1) * whiteKeyWidth - blackKeyWidth / 2, 'black');
    }

    function createKey(x, color) {
      return new app.Key({x: x, color: color, id: i});
    }

    function hasBlackKey(index){
      var i = index % 7;
      return i !== 2 && i !== 6;
    }
  },

  render: function() {
    app.Keyboard.where({color: 'white'}).forEach(function(model) {
      var view = new app.WhiteKeyView({model: model}, model.get('x'));
      this.append( view.render().el );
    }, this.$el);

    app.Keyboard.where({color: 'black'}).forEach(function(model) {
      var view = new app.BlackKeyView({model: model}, model.get('x'));
      this.append( view.render().el );
    }, this.$el);

    this.$el.width(app.Keyboard.where({color: 'white'}).length * app.KeyView.whiteKeyWidth)

    return this;
  },
});

Backbone.sync = function(method, model) {
  console.log("I've been passed " + method + " with " + JSON.stringify(model));
};<commit_msg>Not using sync<commit_after>var app = app || {};

var Keyboard = Backbone.Collection.extend({
  model: app.Key,
});

app.Keyboard = new Keyboard();

app.KeyboardView = Backbone.View.extend({
  el: $('#keyboard'),

  initialize: function() {
    this.listenTo(app.Keyboard, 'reset', this.render);

    app.Keyboard.reset(this.createKeys());
  },

  createKeys: function(){
    var whiteKeyWidth = app.KeyView.whiteKeyWidth;
    var blackKeyWidth = app.KeyView.blackKeyWidth;

    var i = 0, keys = [], octaves = 3;

    for(var index = 0; index < 7 * octaves; index++) {
      i = keys.push(createWhiteKey(index, this.whiteKeyWidth));

      if(hasBlackKey(index)) {
        i = keys.push(createBlackKey(index, this.blackKeyWidth));
      }
    }

    return keys;

    function createWhiteKey(index) {
      return createKey(index * whiteKeyWidth, 'white');
    }

    function createBlackKey(index) {
      return createKey((index + 1) * whiteKeyWidth - blackKeyWidth / 2, 'black');
    }

    function createKey(x, color) {
      return new app.Key({x: x, color: color, id: i});
    }

    function hasBlackKey(index){
      var i = index % 7;
      return i !== 2 && i !== 6;
    }
  },

  render: function() {
    app.Keyboard.where({color: 'white'}).forEach(function(model) {
      var view = new app.WhiteKeyView({model: model}, model.get('x'));
      this.append( view.render().el );
    }, this.$el);

    app.Keyboard.where({color: 'black'}).forEach(function(model) {
      var view = new app.BlackKeyView({model: model}, model.get('x'));
      this.append( view.render().el );
    }, this.$el);

    this.$el.width(app.Keyboard.where({color: 'white'}).length * app.KeyView.whiteKeyWidth)

    return this;
  },
});<|endoftext|>


<commit_before>define([
	"dojo/_base/declare", "./Base", "dojo/on", "dojo/topic",
	"dojo/dom-class", "dijit/layout/ContentPane", "dojo/dom-construct",
	"../formatter", "../TabContainer", "dojo/_base/Deferred",
	"dojo/request", "dojo/_base/lang","dojo/when",
	"../ActionBar", "../ContainerActionBar"
], function(declare, Base, on, Topic,
			domClass, ContentPane, domConstruct,
			formatter, TabContainer, Deferred,
			xhr, lang,when,
			ActionBar
){
	return declare([Base], {
		"disabled": false,
		"query": null,
		"loading": false,
		data: null,
		maxSequences: 500,

		onSetLoading: function(attr, oldVal, loading){
			if (loading){
				this.contentPane.set("content", "
Performing Multiple Sequence Alignment. Please Wait...
");
			}
		},
		checkSequenceCount: function(query){
			var q = query + "&limit(1)";
			console.log("Check Sequence Count: ",this.apiServiceUrl + "/genome_feature/", q );
			var def = new Deferred();
			xhr.post(this.apiServiceUrl + "/genome_feature/",{
				data: q,
				headers:  {
					"accept": "application/solr+json",
          	    	"content-type": "application/rqlquery+x-www-form-urlencoded",
            	    'X-Requested-With': null,
                	'Authorization': (window.App.authorizationToken || "")
                },
                handleAs: "json"
			}).then(lang.hitch(this, function(res){
				console.log("Check Res: ", res.response.numFound)
				if (res && res.response && res.response.numFound && (res.response.numFound < this.maxSequences)){
					console.log("  Amount OK")
					def.resolve(res.response.numFound);
					return;
				}
				console.log("   TOO Many Sequences");
				def.reject(false);
			}))

			return def.promise;
		},
		onSetState: function(attr,oldVal, state){
			console.log("MSA Viewer onSetState: ", state);
			if (state && state.search){
				when(this.checkSequenceCount(state.search), lang.hitch(this, function(ok){
					console.log("CHECK SEQ COUNT ok: ", ok)
					this.doAlignment()
				}), lang.hitch(this, function(){
					this.showError("There are too many sequences in your query.  Please reduce to below 500 Sequences.");
				}))
			}
		},

		showError: function(msg){
			this.contentPane.set('content', '
' + msg + "
");
		},
		onSetData: function(attr,oldVal, data){
			this.render();
		},

		render: function(){
			this.contentPane.set('content', "
" + JSON.stringify(this.data,null,3) + "
");
		},

		doAlignment: function(){
			console.log("doAlignment()");
			this.set('loading', true);
			if (this.state && this.state.search){
				var q = this.state.search;

				console.log("RUN MSA Against: ", this.state.search)
				return when(window.App.api.data("multipleSequenceAlignment",[q]),lang.hitch(this,function(res){
					console.log("MSA Results: ", res);
					this.set('loading', false);
					this.set('data', res);
				}))
			}

		},
		postCreate: function(){
			this.contentPane = new ContentPane({"region": "center"});
			this.addChild(this.contentPane)
		},
		startup: function(){

			if (this._started){return;}

			this.watch("loading", lang.hitch(this, "onSetLoading"));
			this.watch("data", lang.hitch(this, "onSetData"))

			this.inherited(arguments);
		}
	})
});<commit_msg>check number of sequences before attempting to submit<commit_after>define([
	"dojo/_base/declare", "./Base", "dojo/on", "dojo/topic",
	"dojo/dom-class", "dijit/layout/ContentPane", "dojo/dom-construct",
	"../formatter", "../TabContainer", "dojo/_base/Deferred",
	"dojo/request", "dojo/_base/lang","dojo/when",
	"../ActionBar", "../ContainerActionBar"
], function(declare, Base, on, Topic,
			domClass, ContentPane, domConstruct,
			formatter, TabContainer, Deferred,
			xhr, lang,when,
			ActionBar
){
	return declare([Base], {
		"disabled": false,
		"query": null,
		"loading": false,
		data: null,
		maxSequences: 500,

		onSetLoading: function(attr, oldVal, loading){
			if (loading){
				this.contentPane.set("content", "
Performing Multiple Sequence Alignment. Please Wait...
");
			}
		},
		checkSequenceCount: function(query){
			var q = query + "&limit(1)";
			console.log("Check Sequence Count: ",this.apiServiceUrl + "/genome_feature/", q );
			var def = new Deferred();
			xhr.post(this.apiServiceUrl + "/genome_feature/",{
				data: q,
				headers:  {
					"accept": "application/solr+json",
          	    	"content-type": "application/rqlquery+x-www-form-urlencoded",
            	    'X-Requested-With': null,
                	'Authorization': (window.App.authorizationToken || "")
                },
                handleAs: "json"
			}).then(lang.hitch(this, function(res){
				console.log("Check Res: ", res.response.numFound)
				if (res && res.response && (typeof res.response.numFound != 'undefined') && (res.response.numFound < this.maxSequences)){
					console.log("  Amount OK")
					def.resolve(res.response.numFound);
					return;
				}
				console.log("   TOO Many Sequences");
				def.reject(res.response.numFound);
			}))

			return def.promise;
		},
		onSetState: function(attr,oldVal, state){
			console.log("MSA Viewer onSetState: ", state);
			if (state && state.search){
				when(this.checkSequenceCount(state.search), lang.hitch(this, function(count){
					console.log("CHECK SEQ COUNT ok: ", count)
					if (count<2){
						this.showError("There must be at least two matching sequences for a query.  Your query found " + count + " sequences.");
					}else{
						this.doAlignment()
					}
				}), lang.hitch(this, function(count){
					this.showError("There are too many sequences in your query results (" + count + ").  Please reduce to below 500 Sequences.");
				}))
			}
		},

		showError: function(msg){
			this.contentPane.set('content', '
' + msg + "
");
		},
		onSetData: function(attr,oldVal, data){
			this.render();
		},

		render: function(){
			this.contentPane.set('content', "
" + JSON.stringify(this.data,null,3) + "
");
		},

		doAlignment: function(){
			console.log("doAlignment()");
			this.set('loading', true);
			if (this.state && this.state.search){
				var q = this.state.search;

				console.log("RUN MSA Against: ", this.state.search)
				return when(window.App.api.data("multipleSequenceAlignment",[q]),lang.hitch(this,function(res){
					console.log("MSA Results: ", res);
					this.set('loading', false);
					this.set('data', res);
				}))
			}

		},
		postCreate: function(){
			this.contentPane = new ContentPane({"region": "center"});
			this.addChild(this.contentPane)
		},
		startup: function(){

			if (this._started){return;}

			this.watch("loading", lang.hitch(this, "onSetLoading"));
			this.watch("data", lang.hitch(this, "onSetData"))

			this.inherited(arguments);
		}
	})
});<|endoftext|>