Commits

Matthew Schinckel committed ebb6270

Use underscore, it gives me 'this' in .each
Refactor read/write functions.
Move Device to internal class function.
Bind delegate as listener to all our events.

Comments (0)

Files changed (2)

   var plugin;
   var $plugin;
   
-  if (window.ActiveXObject) {
-    // IE
-    $plugin = $('#GarminActiveXControl');
-    if (!$plugin.length) {
-      $plugin = $('<object id="GarminActiveXControl" style="WIDTH: 0px; HEIGHT: 0px; visible: hidden" height="0" width="0" classid="CLSID:099B5A62-DE20-48C6-BF9E-290A9D1D8CB5">');
-      $('body').append($plugin);
+    if (window.ActiveXObject) {
+      // IE
       $plugin = $('#GarminActiveXControl');
+      if (!$plugin.length) {
+        $plugin = $('<object id="GarminActiveXControl" style="WIDTH: 0px; HEIGHT: 0px; visible: hidden" height="0" width="0" classid="CLSID:099B5A62-DE20-48C6-BF9E-290A9D1D8CB5">');
+        $('body').append($plugin);
+        $plugin = $('#GarminActiveXControl');
+      }
+    } else {
+      $plugin = $('#GarminNetscapePlugin');
+      if (!$plugin.length) {
+        $plugin = $('<div style="height:0 px;width:0px"><object id="GarminNetscapePlugin" type="application/vnd-garmin.mygarmin" width="0" height="0">&#160;</object></div>');
+        $('body').append($plugin);
+        $plugin = $('#GarminNetscapePlugin');
+      }
     }
-  } else {
-    $plugin = $('#GarminNetscapePlugin');
-    if (!$plugin.length) {
-      $plugin = $('<div style="height:0 px;width:0px"><object id="GarminNetscapePlugin" type="application/vnd-garmin.mygarmin" width="0" height="0">&#160;</object></div>');
-      $('body').append($plugin);
-      $plugin = $('#GarminNetscapePlugin');
-    }
-  }
+  
   plugin = $plugin[0];
   
   var parseXML = function(xml) {
     finished: 3
   };
   
-  /* 
-  
-  A Device is an abstraction that knows how to read/write
-  from/to itself.
-  
-  Not sure if it will stay here or not. The plugin seems to use 
-  essentially global variables!
-  
-  */
-  Garmin.Device = function Device(plugin, number) {
-    var _cache = {};
-    
-    var $deviceData = parseXML(plugin.DeviceDescription(number));
-    
-    this.displayName = function() {
-      return $deviceData.find('DisplayName').text();
-    };
-    
-    this.progress = function() {
-      var message = {content: []};
-      var data = parseXML(plugin.ProgressXml);
-      message.title = data.find('Title').text();
-      $.each(data.find('Text:not(:empty)'), function(i, el){
-        var $el = $(el);
-        if ($el.text().match(/^[0-9]+%/)) {
-          message.percent = parseInt($el.text(), 10);
-        } else {
-          message.content.push($el.text());
-        }
-      });
-      return message;
-    };
-    
-    // Only while testing.
-    this.plugin = plugin;
+  var FITNESS_TYPES = {
+    Activities: ['FitnessHistory', 'FitnessDirectory'],
+    Workouts: ['FitnessWorkouts', 'FitnessData'],
+    Courses: ['FitnessCourses', 'FitnessData'],
+    Goals: ['FitnessActivityGoals', 'FitnessData'],
+    Profile: ['FitnessUserProfile', 'FitnessData']
   };
   
   Garmin.DeviceControl = function DeviceControl(delegate) {
     // Message sender.
     var send = $plugin.triggerHandler;
     
+    //************** Device class **************//
+    
+    var Device = function Device(number) {
+      var deviceData = parseXML(plugin.DeviceDescription(number));
+      var WRITE = 'Input';
+      var READ = 'Output';
+      
+      // Return a read-only accessor of the deviceData of this name.
+      function readData(name) {
+        return function() {
+          return deviceData.find(name).text();
+        };
+      }
+      
+      function canXY(direction, dataTypeName) {
+        return function() {
+          return deviceData.find('MassStorageMode DataType Name').filter(function() {
+            return $(this).text() === dataTypeName;
+          }).closest('DataType').find('TransferDirection').text().match(direction) || false;
+        };
+      };
+      
+      this.displayName = readData('DisplayName');
+      this.partNumber = readData('Model PartNumber');
+      this.softwareVersion = readData('Model SoftwareVersion');
+      
+      _.each(FITNESS_TYPES, function(data, type) {
+        this['canRead' + type] = canXY(READ, data[0]);
+        this['canWrite' + type] = canXY(WRITE, data[0]);
+      }, this);
+    }
+    
     //************** Helpers **************//
     
     var checkUnlocked = function() {
     };
     
     var reportException = function(e) {
-      
+      send('onException', e);
     };
     
-
+    var progress = function() {
+      var message = {content: []};
+      var data = parseXML(plugin.ProgressXml);
+      message.title = data.find('Title').text();
+      $.each(data.find('Text:not(:empty)'), function(i, el){
+        var $el = $(el);
+        if ($el.text().match(/^[0-9]+%/)) {
+          message.percent = parseInt($el.text(), 10);
+        } else {
+          message.content.push($el.text());
+        }
+      });
+      return message;
+    };
+    
+    //************** Bind delegate event listeners **************//
+    
+    var EVENTS = [
+      'onStartFindDevices', 'onCancelFindDevices', 'onFinishFindDevices',
+      'onException', 'onInteractionWithNoDevice',
+      'onStartReadFromDevice', 'onWaitingReadFromDevice', 'onProgressReadFromDevice', 'onCancelReadFromDevice', 'onFinishReadFromDevice',
+      'onStartWriteToDevice', 'onWaitingWriteToDevice', 'onProgressWriteToDevice', 'onCancelWriteToDevice', 'onFinishWriteToDevice'
+    ];
+    
+    delegate = delegate || {};
+    // Bind any listeners that we find on the delegate object
+    _.each(EVENTS, function(evt) {
+      if (delegate[evt]) {
+        $plugin.bind(evt, delegate[evt]);        
+      }
+    });
     
     //************** Handlers **************//
     
         if (plugin.FinishFindDevices()) {
           var data = parseXML(plugin.DevicesXmlString());
           devices = [];
-          $.each(data.find('Device'), function(i, el) {
-            devices.push(new Garmin.Device(plugin, i));
+          _.each(data.find('Device'), function(el,i) {
+            devices.push(new Device(i));
           });
           send('onFinishFindDevices', {devices: devices});
         } else {
       return devices[d];
     };
     
-    this.deviceData = function() {
-      
+    this.activeDevice = function() {
+      return devices[currentDevice];
     };
-    
-    var hasProperty = function hasProperty(obj, prop) {
-      return (typeof obj[prop] !== 'undefined') || obj[prop];
-    };
-    
+            
     var baseHandler = function(readWrite, dataType, pluginMethod) {
       if (currentDevice == null) {
-        throw new Error("Select a device first");
+        send('onInteractionWithNoDevice');
+        return;
+      }
+      if (inUse) {
+        send('onConcurrentDeviceEvent');
+        return;
       }
       var device = devices[currentDevice];
       var toFrom;
         toFrom = "From";
         readWrite = "Read";
       }
+      inUse = true;
       send('onStart' + readWrite + toFrom + 'Device', {device:device, dataType:dataType});
-      console.log('Start' + readWrite + pluginMethod, dataType);
       plugin['Start' + readWrite + pluginMethod](currentDevice, dataType);
       
-      var finishReadFromDevice = function finishReadFromDevice() {
-        var progress = device.progress();
-        send('onProgress' + readWrite + toFrom + 'Device', {device: device, progress: progress});
+      var finishHandler = function finishHandler() {
+        send('onProgress' + readWrite + toFrom + 'Device', {device: device, progress: progress()});
         switch (plugin['Finish' + readWrite + pluginMethod]()) {
           case PROGRESS.working:
-            setTimeout(finishReadFromDevice, 200);
+            setTimeout(finishHandler, 200);
             break;
           case PROGRESS.finished:
-            send('onFinishReadFromDevice', {device:device, dataType: dataType, data: plugin.TcdXml});
-            console.log('Finished.');
-            console.log((readWrite == 'Read' ? 'Read ' : 'Wrote ') + plugin.TcdXml.length + ' bytes.');
+            send('onFinish' + readWrite + toFrom  + 'Device', {device:device, dataType: dataType, data: plugin.TcdXml});
+            inUse = false;
             break;
           default:
-            console.log(plugin['Finish' + readWrite + pluginMethod]());
             break;
         }
       };
       
-      finishReadFromDevice();
+      finishHandler();
     };
     
     var readHandler = function(dataType, pluginMethod) {
       };
     };
     
-    this.readActivities = readHandler('FitnessHistory', 'FitnessDirectory');
-    this.writeActivities = writeHandler('FitnessHistory', 'FitnessDirectory');
+    _.each(FITNESS_TYPES, function(data, type) {
+      this['read' + type] = readHandler(data[0], data[1]);
+      this['write' + type] = writeHandler(data[0], data[1]);
+    }, this);
     
-    this.readWorkouts = readHandler('FitnessWorkouts', 'FitnessData');
-    this.writeWorkouts = writeHandler('FitnessWorkouts', 'FitnessData');
-    
-    this.readCourses = readHandler('FitnessCourses', 'FitnessData')
-    this.writeCourses = writeHandler('FitnessCourses', 'FitnessData');
-    
-    this.readProfile = readHandler('FitnessUserProfile', 'FitnessData');
-    this.writeProfile = writeHandler('FitnessUserProfile', 'FitnessData');
-    
-    // For some reason this one is not reading or writing yet.
-    this.readGoals = readHandler('FitnessActivityGoals', 'FitnessData');
-    this.writeGoals = writeHandler('FitnessActivityGoals', 'FitnessData');
-  }
+    // Only while developing!
+    this.plugin = plugin;
+  };
 })(jQuery);
 
 var g = new Garmin.DeviceControl();

tests/basic_test.html

   <head></head>
   <body>
     <script src="../vendor/jquery-1.7.2.js"></script>
+    <script src="../vendor/underscore-1.3.3.js"></script>
     <script src="../src/garmin.js"></script>
     <textarea>