<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

/**
 * @fileoverview JSON-RPC based opensocial container.
 */

var JsonRpcContainer = function(baseUrl, domain, supportedFieldsArray) {
  opensocial.Container.call(this);

  var supportedFieldsMap = {};
  for (var objectType in supportedFieldsArray) {
    if (supportedFieldsArray.hasOwnProperty(objectType)) {
      supportedFieldsMap[objectType] = {};
      for (var i = 0; i < supportedFieldsArray[objectType].length; i++) {
        var supportedField = supportedFieldsArray[objectType][i];
        supportedFieldsMap[objectType][supportedField] = true;
      }
    }
  }

  this.environment_ = new opensocial.Environment(domain, supportedFieldsMap);
  this.baseUrl_ = baseUrl;

  this.securityToken_ = shindig.auth.getSecurityToken();
};
JsonRpcContainer.inherits(opensocial.Container);

JsonRpcContainer.prototype.getEnvironment = function() {
  return this.environment_;
};

JsonRpcContainer.prototype.requestCreateActivity = function(activity, priority,
    opt_callback) {
  opt_callback = opt_callback || {};

  var req = opensocial.newDataRequest();
  var viewer = new opensocial.IdSpec({'userId' : 'VIEWER'});
  req.add(this.newCreateActivityRequest(viewer, activity), 'key');
  req.send(function(response) {
    opt_callback(response.get('key'));
  });
};

JsonRpcContainer.prototype.requestData = function(dataRequest, callback) {
  callback = callback || {};

  var requestObjects = dataRequest.getRequestObjects();
  var totalRequests = requestObjects.length;

  if (totalRequests == 0) {
    callback(new opensocial.DataResponse({}, true));
    return;
  }

  var jsonBatchData = new Array(totalRequests);

  for (var j = 0; j < totalRequests; j++) {
    var requestObject = requestObjects[j];

    jsonBatchData[j] = requestObject.request.rpc;
    if (requestObject.key) {
      jsonBatchData[j].id = requestObject.key;
    }
  }

  var sendResponse = function(result) {
    if (result.errors[0]) {
      JsonRpcContainer.generateErrorResponse(result, requestObjects, callback);
      return;
    }

    result = result.data;

    var globalError = false;
    var responseMap = {};

    // Map from indices to ids.
    for (var i = 0; i < result.length; i++) {
      result[result[i].id] = result[i];
    }

    for (var k = 0; k < requestObjects.length; k++) {
      var request = requestObjects[k];
      var response = result[k];

      if (request.key && response.id != request.key) {
        throw "Request key(" + request.key +
            ") and response id(" + response.id + ") do not match";
      }

      var rawData = response.data;
      var error = response.error;
      var errorMessage = "";

      if (error) {
        errorMessage = error.message;
      }

      var processedData = request.request.processResponse(
          request.request, rawData, error, errorMessage);
      globalError = globalError || processedData.hadError();
      if (request.key) {
        responseMap[request.key] = processedData;
      }
    }

    var dataResponse = new opensocial.DataResponse(responseMap, globalError);
    callback(dataResponse);
  };

  // TODO: get the jsonbatch url from the container config
  var makeRequestParams = {
    "CONTENT_TYPE" : "JSON",
    "METHOD" : "POST",
    "AUTHORIZATION" : "SIGNED",
    "POST_DATA" : gadgets.json.stringify(jsonBatchData)
  };

  gadgets.io.makeNonProxiedRequest(
      this.baseUrl_ + "/rpc?st=" +
      encodeURIComponent(shindig.auth.getSecurityToken()),
      sendResponse, makeRequestParams, "application/json");
};

JsonRpcContainer.generateErrorResponse = function(result, requestObjects,
    callback) {
  var globalErrorCode =
          JsonRpcContainer.translateHttpError(result.errors[0]
                  || result.data.error)
                  || opensocial.ResponseItem.Error.INTERNAL_ERROR;

  var errorResponseMap = {};
  for (var i = 0; i < requestObjects.length; i++) {
    errorResponseMap[requestObjects[i].key] = new opensocial.ResponseItem(
        requestObjects[i].request, null, globalErrorCode);
  }
  callback(new opensocial.DataResponse(errorResponseMap, true));
};

JsonRpcContainer.translateHttpError = function(httpError) {
  if (httpError == "Error 501") {
    return opensocial.ResponseItem.Error.NOT_IMPLEMENTED;
  } else if (httpError == "Error 401") {
    return opensocial.ResponseItem.Error.UNAUTHORIZED;
  } else if (httpError == "Error 403") {
    return opensocial.ResponseItem.Error.FORBIDDEN;
  } else if (httpError == "Error 400") {
    return opensocial.ResponseItem.Error.BAD_REQUEST;
  } else if (httpError == "Error 500") {
    return opensocial.ResponseItem.Error.INTERNAL_ERROR;
  } else if (httpError == "Error 404") {
    return opensocial.ResponseItem.Error.BAD_REQUEST;
  } else if (httpError == "Error 417") {
    return opensocial.ResponseItem.Error.LIMIT_EXCEEDED;
  }
};

JsonRpcContainer.prototype.makeIdSpec = function(id) {
  return new opensocial.IdSpec({'userId' : id});
};

JsonRpcContainer.prototype.translateIdSpec = function(newIdSpec) {
  var userIds = newIdSpec.getField('userId');
  var groupId = newIdSpec.getField('groupId');

  // Upconvert to array for convenience
  if (!opensocial.Container.isArray(userIds)) {
    userIds = [userIds];
  }

  for (var i = 0; i < userIds.length; i++) {
    if (userIds[i] == 'OWNER') {
      userIds[i] = '@owner';
    } else if (userIds[i] == 'VIEWER') {
      userIds[i] = '@viewer';
    }
  }

  if (groupId == 'FRIENDS') {
    groupId = "@friends";
  } else if (groupId == 'SELF' || !groupId) {
    groupId = "@self";
  }

  return { userId : userIds, groupId : groupId};
};

JsonRpcContainer.prototype.newFetchPersonRequest = function(id, opt_params) {
  var peopleRequest = this.newFetchPeopleRequest(
      this.makeIdSpec(id), opt_params);

  var me = this;
  return new JsonRpcRequestItem(peopleRequest.rpc,
          function(rawJson) {
            return me.createPersonFromJson(rawJson);
          });
};

JsonRpcContainer.prototype.newFetchPeopleRequest = function(idSpec,
    opt_params) {
  var rpc = { method : "people.get" };
  rpc.params = this.translateIdSpec(idSpec);
  if (opt_params['profileDetail']) {
    FieldTranslations.translateJsPersonFieldsToServerFields(opt_params['profileDetail']);
    rpc.params.fields = opt_params['profileDetail'];
  }
  if (opt_params['first']) {
    rpc.params.startIndex = opt_params['first'];
  }
  if (opt_params['max']) {
    rpc.params.count = opt_params['max'];
  }
  if (opt_params['sortOrder']) {
    rpc.params.sortBy = opt_params['sortOrder'];
  }
  if (opt_params['filter']) {
    rpc.params.filterBy = opt_params['filter'];
  }
  if (idSpec.getField('networkDistance')) {
    rpc.params.networkDistance = idSpec.getField('networkDistance');
  }

  var me = this;
  return new JsonRpcRequestItem(rpc,
      function(rawJson) {
        var jsonPeople;
        if (rawJson['list']) {
          // For the array of people response
          jsonPeople = rawJson['list'];
        } else {
          // For the single person response
          jsonPeople = [rawJson];
        }

        var people = [];
        for (var i = 0; i < jsonPeople.length; i++) {
          people.push(me.createPersonFromJson(jsonPeople[i]));
        }
        return new opensocial.Collection(people,
            rawJson['startIndex'], rawJson['totalResults']);
      });
};

JsonRpcContainer.prototype.createPersonFromJson = function(serverJson) {
  FieldTranslations.translateServerPersonToJsPerson(serverJson);
  return new JsonPerson(serverJson);
};

JsonRpcContainer.prototype.getFieldsList = function(keys) {
  // datarequest.js guarantees that keys is an array
  if (this.hasNoKeys(keys) || this.isWildcardKey(keys[0])) {
    return [];
  } else {
    return keys;
  }
};

JsonRpcContainer.prototype.hasNoKeys = function(keys) {
  return !keys || keys.length == 0;
};

JsonRpcContainer.prototype.isWildcardKey = function(key) {
  // Some containers support * to mean all keys in the js apis.
  // This allows the RESTful apis to be compatible with them.
  return key == "*";
};

JsonRpcContainer.prototype.newFetchPersonAppDataRequest = function(idSpec, keys,
    opt_params) {
  var rpc = { method : "appdata.get" };
  rpc.params = this.translateIdSpec(idSpec);
  rpc.params.appId = "@app";
  rpc.params.fields = this.getFieldsList(keys);
  if (idSpec.getField('networkDistance')) {
    rpc.params.networkDistance = idSpec.getField('networkDistance');
  }

  return new JsonRpcRequestItem(rpc,
      function (appData) {
        return opensocial.Container.escape(appData, opt_params, true);
      });
};

JsonRpcContainer.prototype.newUpdatePersonAppDataRequest = function(id, key,
    value) {
  var rpc = { method : "appdata.update" };
  rpc.params = this.translateIdSpec(this.makeIdSpec(id));
  rpc.params.appId = "@app";
  rpc.params.data = {};
  rpc.params.data[key] = value;
  rpc.params.fields = key;
  return new JsonRpcRequestItem(rpc);
};

JsonRpcContainer.prototype.newRemovePersonAppDataRequest = function(id, keys) {
  var rpc = { method : "appdata.delete" };
  rpc.params = this.translateIdSpec(this.makeIdSpec(id));
  rpc.params.appId = "@app";
  rpc.params.fields = this.getFieldsList(keys);

  return new JsonRpcRequestItem(rpc);
};

JsonRpcContainer.prototype.newFetchActivitiesRequest = function(idSpec,
    opt_params) {
  var rpc = { method : "activities.get" };
  rpc.params = this.translateIdSpec(idSpec);
  rpc.params.appId = "@app";
  if (idSpec.getField('networkDistance')) {
    rpc.params.networkDistance = idSpec.getField('networkDistance');
  }

  return new JsonRpcRequestItem(rpc,
      function(rawJson) {
        rawJson = rawJson['list'];
        var activities = [];
        for (var i = 0; i < rawJson.length; i++) {
          activities.push(new JsonActivity(rawJson[i]));
        }
        return new opensocial.Collection(activities);
      });
};

JsonRpcContainer.prototype.newActivity = function(opt_params) {
  return new JsonActivity(opt_params, true);
};

JsonRpcContainer.prototype.newMediaItem = function(mimeType, url, opt_params) {
  opt_params = opt_params || {};
  opt_params['mimeType'] = mimeType;
  opt_params['url'] = url;
  return new JsonMediaItem(opt_params);
};

JsonRpcContainer.prototype.newCreateActivityRequest = function(idSpec,
    activity) {
  var rpc = { method : "activities.create" };
  rpc.params = this.translateIdSpec(idSpec);
  rpc.params.appId = "@app";
  if (idSpec.getField('networkDistance')) {
    rpc.params.networkDistance = idSpec.getField('networkDistance');
  }
  rpc.params.activity = activity.toJsonObject();

  return new JsonRpcRequestItem(rpc);
};

var JsonRpcRequestItem = function(rpc, opt_processData) {
  this.rpc = rpc;
  this.processData = opt_processData ||
                     function (rawJson) {
                       return rawJson;
                     };

  this.processResponse = function(originalDataRequest, rawJson, error,
      errorMessage) {
    var errorCode = error
      ? JsonRpcContainer.translateHttpError("Error " + error['code'])
      : null;
    return new opensocial.ResponseItem(originalDataRequest,
        error ? null : this.processData(rawJson), errorCode, errorMessage);
  }
};
<commit_msg>Applied patch from Adam Winer for JIRA issue SHINDIG-596<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

/**
 * @fileoverview JSON-RPC based opensocial container.
 */

var JsonRpcContainer = function(baseUrl, domain, supportedFieldsArray) {
  opensocial.Container.call(this);

  var supportedFieldsMap = {};
  for (var objectType in supportedFieldsArray) {
    if (supportedFieldsArray.hasOwnProperty(objectType)) {
      supportedFieldsMap[objectType] = {};
      for (var i = 0; i < supportedFieldsArray[objectType].length; i++) {
        var supportedField = supportedFieldsArray[objectType][i];
        supportedFieldsMap[objectType][supportedField] = true;
      }
    }
  }

  this.environment_ = new opensocial.Environment(domain, supportedFieldsMap);
  this.baseUrl_ = baseUrl;

  this.securityToken_ = shindig.auth.getSecurityToken();
};
JsonRpcContainer.inherits(opensocial.Container);

JsonRpcContainer.prototype.getEnvironment = function() {
  return this.environment_;
};

JsonRpcContainer.prototype.requestCreateActivity = function(activity, priority,
    opt_callback) {
  opt_callback = opt_callback || {};

  var req = opensocial.newDataRequest();
  var viewer = new opensocial.IdSpec({'userId' : 'VIEWER'});
  req.add(this.newCreateActivityRequest(viewer, activity), 'key');
  req.send(function(response) {
    opt_callback(response.get('key'));
  });
};

JsonRpcContainer.prototype.requestData = function(dataRequest, callback) {
  callback = callback || {};

  var requestObjects = dataRequest.getRequestObjects();
  var totalRequests = requestObjects.length;

  if (totalRequests == 0) {
    callback(new opensocial.DataResponse({}, true));
    return;
  }

  var jsonBatchData = new Array(totalRequests);

  for (var j = 0; j < totalRequests; j++) {
    var requestObject = requestObjects[j];

    jsonBatchData[j] = requestObject.request.rpc;
    if (requestObject.key) {
      jsonBatchData[j].id = requestObject.key;
    }
  }

  var sendResponse = function(result) {
    if (result.errors[0]) {
      JsonRpcContainer.generateErrorResponse(result, requestObjects, callback);
      return;
    }

    result = result.data;

    var globalError = false;
    var responseMap = {};

    // Map from indices to ids.
    for (var i = 0; i < result.length; i++) {
      result[result[i].id] = result[i];
    }

    for (var k = 0; k < requestObjects.length; k++) {
      var request = requestObjects[k];
      var response = result[k];

      if (request.key && response.id != request.key) {
        throw "Request key(" + request.key +
            ") and response id(" + response.id + ") do not match";
      }

      var rawData = response.data;
      var error = response.error;
      var errorMessage = "";

      if (error) {
        errorMessage = error.message;
      }

      var processedData = request.request.processResponse(
          request.request, rawData, error, errorMessage);
      globalError = globalError || processedData.hadError();
      if (request.key) {
        responseMap[request.key] = processedData;
      }
    }

    var dataResponse = new opensocial.DataResponse(responseMap, globalError);
    callback(dataResponse);
  };

  // TODO: get the jsonbatch url from the container config
  var makeRequestParams = {
    "CONTENT_TYPE" : "JSON",
    "METHOD" : "POST",
    "AUTHORIZATION" : "SIGNED",
    "POST_DATA" : gadgets.json.stringify(jsonBatchData)
  };

  this.sendRequest(this.baseUrl_ + "/rpc?st=" +
      encodeURIComponent(shindig.auth.getSecurityToken()),
      sendResponse, makeRequestParams, "application/json");
};

JsonRpcContainer.prototype.sendRequest = function(relativeUrl, callback, params, contentType) {
  gadgets.io.makeNonProxiedRequest(relativeUrl, callback, params, contentType);
}

JsonRpcContainer.generateErrorResponse = function(result, requestObjects,
    callback) {
  var globalErrorCode =
          JsonRpcContainer.translateHttpError(result.errors[0]
                  || result.data.error)
                  || opensocial.ResponseItem.Error.INTERNAL_ERROR;

  var errorResponseMap = {};
  for (var i = 0; i < requestObjects.length; i++) {
    errorResponseMap[requestObjects[i].key] = new opensocial.ResponseItem(
        requestObjects[i].request, null, globalErrorCode);
  }
  callback(new opensocial.DataResponse(errorResponseMap, true));
};

JsonRpcContainer.translateHttpError = function(httpError) {
  if (httpError == "Error 501") {
    return opensocial.ResponseItem.Error.NOT_IMPLEMENTED;
  } else if (httpError == "Error 401") {
    return opensocial.ResponseItem.Error.UNAUTHORIZED;
  } else if (httpError == "Error 403") {
    return opensocial.ResponseItem.Error.FORBIDDEN;
  } else if (httpError == "Error 400") {
    return opensocial.ResponseItem.Error.BAD_REQUEST;
  } else if (httpError == "Error 500") {
    return opensocial.ResponseItem.Error.INTERNAL_ERROR;
  } else if (httpError == "Error 404") {
    return opensocial.ResponseItem.Error.BAD_REQUEST;
  } else if (httpError == "Error 417") {
    return opensocial.ResponseItem.Error.LIMIT_EXCEEDED;
  }
};

JsonRpcContainer.prototype.makeIdSpec = function(id) {
  return new opensocial.IdSpec({'userId' : id});
};

JsonRpcContainer.prototype.translateIdSpec = function(newIdSpec) {
  var userIds = newIdSpec.getField('userId');
  var groupId = newIdSpec.getField('groupId');

  // Upconvert to array for convenience
  if (!opensocial.Container.isArray(userIds)) {
    userIds = [userIds];
  }

  for (var i = 0; i < userIds.length; i++) {
    if (userIds[i] == 'OWNER') {
      userIds[i] = '@owner';
    } else if (userIds[i] == 'VIEWER') {
      userIds[i] = '@viewer';
    }
  }

  if (groupId == 'FRIENDS') {
    groupId = "@friends";
  } else if (groupId == 'SELF' || !groupId) {
    groupId = "@self";
  }

  return { userId : userIds, groupId : groupId};
};

JsonRpcContainer.prototype.newFetchPersonRequest = function(id, opt_params) {
  var peopleRequest = this.newFetchPeopleRequest(
      this.makeIdSpec(id), opt_params);

  var me = this;
  return new JsonRpcRequestItem(peopleRequest.rpc,
          function(rawJson) {
            return me.createPersonFromJson(rawJson);
          });
};

JsonRpcContainer.prototype.newFetchPeopleRequest = function(idSpec,
    opt_params) {
  var rpc = { method : "people.get" };
  rpc.params = this.translateIdSpec(idSpec);
  if (opt_params['profileDetail']) {
    FieldTranslations.translateJsPersonFieldsToServerFields(opt_params['profileDetail']);
    rpc.params.fields = opt_params['profileDetail'];
  }
  if (opt_params['first']) {
    rpc.params.startIndex = opt_params['first'];
  }
  if (opt_params['max']) {
    rpc.params.count = opt_params['max'];
  }
  if (opt_params['sortOrder']) {
    rpc.params.sortBy = opt_params['sortOrder'];
  }
  if (opt_params['filter']) {
    rpc.params.filterBy = opt_params['filter'];
  }
  if (idSpec.getField('networkDistance')) {
    rpc.params.networkDistance = idSpec.getField('networkDistance');
  }

  var me = this;
  return new JsonRpcRequestItem(rpc,
      function(rawJson) {
        var jsonPeople;
        if (rawJson['list']) {
          // For the array of people response
          jsonPeople = rawJson['list'];
        } else {
          // For the single person response
          jsonPeople = [rawJson];
        }

        var people = [];
        for (var i = 0; i < jsonPeople.length; i++) {
          people.push(me.createPersonFromJson(jsonPeople[i]));
        }
        return new opensocial.Collection(people,
            rawJson['startIndex'], rawJson['totalResults']);
      });
};

JsonRpcContainer.prototype.createPersonFromJson = function(serverJson) {
  FieldTranslations.translateServerPersonToJsPerson(serverJson);
  return new JsonPerson(serverJson);
};

JsonRpcContainer.prototype.getFieldsList = function(keys) {
  // datarequest.js guarantees that keys is an array
  if (this.hasNoKeys(keys) || this.isWildcardKey(keys[0])) {
    return [];
  } else {
    return keys;
  }
};

JsonRpcContainer.prototype.hasNoKeys = function(keys) {
  return !keys || keys.length == 0;
};

JsonRpcContainer.prototype.isWildcardKey = function(key) {
  // Some containers support * to mean all keys in the js apis.
  // This allows the RESTful apis to be compatible with them.
  return key == "*";
};

JsonRpcContainer.prototype.newFetchPersonAppDataRequest = function(idSpec, keys,
    opt_params) {
  var rpc = { method : "appdata.get" };
  rpc.params = this.translateIdSpec(idSpec);
  rpc.params.appId = "@app";
  rpc.params.fields = this.getFieldsList(keys);
  if (idSpec.getField('networkDistance')) {
    rpc.params.networkDistance = idSpec.getField('networkDistance');
  }

  return new JsonRpcRequestItem(rpc,
      function (appData) {
        return opensocial.Container.escape(appData, opt_params, true);
      });
};

JsonRpcContainer.prototype.newUpdatePersonAppDataRequest = function(id, key,
    value) {
  var rpc = { method : "appdata.update" };
  rpc.params = this.translateIdSpec(this.makeIdSpec(id));
  rpc.params.appId = "@app";
  rpc.params.data = {};
  rpc.params.data[key] = value;
  rpc.params.fields = key;
  return new JsonRpcRequestItem(rpc);
};

JsonRpcContainer.prototype.newRemovePersonAppDataRequest = function(id, keys) {
  var rpc = { method : "appdata.delete" };
  rpc.params = this.translateIdSpec(this.makeIdSpec(id));
  rpc.params.appId = "@app";
  rpc.params.fields = this.getFieldsList(keys);

  return new JsonRpcRequestItem(rpc);
};

JsonRpcContainer.prototype.newFetchActivitiesRequest = function(idSpec,
    opt_params) {
  var rpc = { method : "activities.get" };
  rpc.params = this.translateIdSpec(idSpec);
  rpc.params.appId = "@app";
  if (idSpec.getField('networkDistance')) {
    rpc.params.networkDistance = idSpec.getField('networkDistance');
  }

  return new JsonRpcRequestItem(rpc,
      function(rawJson) {
        rawJson = rawJson['list'];
        var activities = [];
        for (var i = 0; i < rawJson.length; i++) {
          activities.push(new JsonActivity(rawJson[i]));
        }
        return new opensocial.Collection(activities);
      });
};

JsonRpcContainer.prototype.newActivity = function(opt_params) {
  return new JsonActivity(opt_params, true);
};

JsonRpcContainer.prototype.newMediaItem = function(mimeType, url, opt_params) {
  opt_params = opt_params || {};
  opt_params['mimeType'] = mimeType;
  opt_params['url'] = url;
  return new JsonMediaItem(opt_params);
};

JsonRpcContainer.prototype.newCreateActivityRequest = function(idSpec,
    activity) {
  var rpc = { method : "activities.create" };
  rpc.params = this.translateIdSpec(idSpec);
  rpc.params.appId = "@app";
  if (idSpec.getField('networkDistance')) {
    rpc.params.networkDistance = idSpec.getField('networkDistance');
  }
  rpc.params.activity = activity.toJsonObject();

  return new JsonRpcRequestItem(rpc);
};

var JsonRpcRequestItem = function(rpc, opt_processData) {
  this.rpc = rpc;
  this.processData = opt_processData ||
                     function (rawJson) {
                       return rawJson;
                     };

  this.processResponse = function(originalDataRequest, rawJson, error,
      errorMessage) {
    var errorCode = error
      ? JsonRpcContainer.translateHttpError("Error " + error['code'])
      : null;
    return new opensocial.ResponseItem(originalDataRequest,
        error ? null : this.processData(rawJson), errorCode, errorMessage);
  }
};
<|endoftext|>


<commit_before>/**
 * Node.js envinronment initializer for Left.js
 *
 * Copyright (C) 2011 Nikolay Nemshilov
 */
var

fs  = require('fs'),
sys = require('sys'),

// packing and initializing LeftJS
dir = process.cwd() + "/src/",
modules = ['core', 'dom', 'old', 'form', 'ajax', 'lang', 'sugar', 'legacy'],
sources = {}, i = 0, src;

for (; i < modules.length; i++) {
  src = fs.readFileSync(dir + modules[i] + '.js').toString();
  src = src.replace(/require\(['"](.+?)['"]\);/mg, function(m, filename) {
    return fs.readFileSync(dir + filename + '.js')
      .toString().replace(/($|\n)/g, '$1  ') + "\n\n";
  });

  sources[modules[i]] = src;

  fs.writeFileSync(process.cwd() + "/build/"+ modules[i] + "-src.js", src);

  if (modules[i] == 'core') {
    eval(src);
  }
}

exports.Source = sources;

// globalizing those ones so we didn't need to reinit them all the time
global.LeftJS  = LeftJS;
global.util    = require('util');
global.vows    = require('vows');
global.assert  = require('assert');

assert.same    = assert.strictEqual;
assert.notSame = assert.notStrictEqual;

/**
 * A simple shortcut over the Vows to make
 * a single batch descriptions
 *
 * @param {String} name
 * @param {Object} batch hash
 * @param {Object} current module
 * @return void
 */
global.describe = function(thing, batch, module) {
  vows.describe(thing).addBatch(batch).export(module);
}

// making a little local server with 'express' to load the fixtures into the zombie
var express = require('express');
var server  = express.createServer();

server.use(express.bodyParser());
server.use(express.cookieParser());

server.get('/', function(req, resp) {
  resp.send('Hello');
});

for (var module in sources) {
  server.get(
    '/'+ (module === 'core' ? 'left' : module) + '.js',
    (function(source) {
      return function(req, resp) {
        resp.send(source);
      }
    })(sources[module])
  );
}

global.server = server;

/**
 * A shortcut to dynamically define the server responses
 *
 * @param {Object} routes and responses
 * @return {undefined}
 */
global.server_respond = function(defs) {
  for (var route in defs) {
    (function(route, response) {
      server.get(route, function(req, resp) {
        resp.send(response);
      });
    })(route, defs[route]);
  }
}

// a global zombie-browser reference
global.Browser = require('zombie').Browser;

/**
 * Our own shortcut for the browser load
 * so that you didn't need to carry around
 * the domain-name, port and things
 *
 * @param {String} relative url address
 * @param {Function} vows async callback
 */
Browser.open = function(url, callback) {
  if (!server.active) {
    server.listen(3000);
    server.active = true;
  }

  var browser = new Browser();

  browser.alerts = [];
  browser.onalert(function(message) {
    browser.alerts.push(message);
  });

  browser.visit('http://localhost:3000' + url, function(err, browser) {
    if (err) throw err;
    browser.wait(callback);
  });
}
<commit_msg>Making the tests run<commit_after>/**
 * Node.js envinronment initializer for Left.js
 *
 * Copyright (C) 2011 Nikolay Nemshilov
 */
var

fs  = require('fs'),
sys = require('sys'),

// packing and initializing LeftJS
dir = process.cwd() + "/src/",
modules = ['core', 'dom', 'old', 'form', 'ajax', 'lang', 'sugar', 'legacy'],
sources = {}, i = 0, src;

for (; i < modules.length; i++) {
  dir = process.cwd() + (modules[i] === 'core' ? '/src/' : '/stl/');
  src = fs.readFileSync(dir + modules[i] + '.js').toString();
  src = src.replace(/require\(['"](.+?)['"]\);/mg, function(m, filename) {
    return fs.readFileSync(dir + filename + '.js')
      .toString().replace(/($|\n)/g, '$1  ') + "\n\n";
  });

  sources[modules[i]] = src;

  fs.writeFileSync(process.cwd() + "/build/"+ modules[i] + "-src.js", src);

  if (modules[i] == 'core') {
    eval(src);
  }
}

exports.Source = sources;

// globalizing those ones so we didn't need to reinit them all the time
global.LeftJS  = LeftJS;
global.util    = require('util');
global.vows    = require('vows');
global.assert  = require('assert');

assert.same    = assert.strictEqual;
assert.notSame = assert.notStrictEqual;

/**
 * A simple shortcut over the Vows to make
 * a single batch descriptions
 *
 * @param {String} name
 * @param {Object} batch hash
 * @param {Object} current module
 * @return void
 */
global.describe = function(thing, batch, module) {
  vows.describe(thing).addBatch(batch).export(module);
}

// making a little local server with 'express' to load the fixtures into the zombie
var express = require('express');
var server  = express.createServer();

server.use(express.bodyParser());
server.use(express.cookieParser());

server.get('/', function(req, resp) {
  resp.send('Hello');
});

for (var module in sources) {
  server.get(
    '/'+ (module === 'core' ? 'left' : module) + '.js',
    (function(source) {
      return function(req, resp) {
        resp.send(source);
      }
    })(sources[module])
  );
}

global.server = server;

/**
 * A shortcut to dynamically define the server responses
 *
 * @param {Object} routes and responses
 * @return {undefined}
 */
global.server_respond = function(defs) {
  for (var route in defs) {
    (function(route, response) {
      server.get(route, function(req, resp) {
        resp.send(response);
      });
    })(route, defs[route]);
  }
}

// a global zombie-browser reference
global.Browser = require('zombie').Browser;

/**
 * Our own shortcut for the browser load
 * so that you didn't need to carry around
 * the domain-name, port and things
 *
 * @param {String} relative url address
 * @param {Function} vows async callback
 */
Browser.open = function(url, callback) {
  if (!server.active) {
    server.listen(3000);
    server.active = true;
  }

  var browser = new Browser();

  browser.alerts = [];
  browser.onalert(function(message) {
    browser.alerts.push(message);
  });

  browser.visit('http://localhost:3000' + url, function(err, browser) {
    if (err) throw err;
    browser.wait(callback);
  });
}
<|endoftext|>


<commit_before>/**
 * Created by dll on 15/10/11.
 */

var bookSearch = require("../service/book-search-service");

function search(req, res, next) {
    var isbn = req.query.isbn;
    if (!isbn) {
        res.status(400).send({
            message: "isbn is required."
        });
        return;
    }
    bookSearch.findByIsbn(isbn, function (err, data) {
        if (err) {
            res.send({
                code: 400,
                msg: "search book by isbn err"
            });
        } else {
            res.json(data);
        }
    });
}

module.exports = {
    search: search
}
<commit_msg>when book not exist , give a friendly result<commit_after>/**
 * Created by dll on 15/10/11.
 */

var bookSearch = require("../service/book-search-service");

function search(req, res, next) {
    var isbn = req.query.isbn;
    if (!isbn) {
        res.status(400).send({
            message: "isbn is required."
        });
        return;
    }
    bookSearch.findByIsbn(isbn, function (err, data) {
        if (err) {
            res.send({
                code: 400,
                msg: "search book by isbn err"
            });
        } else {
            if (data) {
                res.json(data);
            } else {
                res.status(404).send({
                    message:'the book not found'
                });
                return;
            }
        }
    });
}

module.exports = {
    search: search
}
<|endoftext|>


<commit_before>
const { app } = nodeRequire('electron').remote;
const path = nodeRequire("path");
const exec = nodeRequire('child_process').exec;
const spawn = nodeRequire('child_process').spawn;
const iconv = nodeRequire('iconv-lite');

var randomtime = 'RFEditor' + (new Date()).valueOf();

var temp_dir = path.join(app.getPath('temp'), randomtime);

var argfile_path = path.join(temp_dir, 'argfile.txt');

var runing_log_path = path.join(temp_dir, 'runing.txt');

jetpack.write(runing_log_path, '');

var runing_console_path = path.join(temp_dir, 'runing_console.txt');

jetpack.write(runing_console_path, '');

watch_running_log_file();

console.log(temp_dir);

function runTest() {

    $('#console_log').html('');
    $('#running_log').html('');

    var checked_nodes = zTree.getCheckedNodes(true);

    argfile_data = ['--outputdir', temp_dir, '-C', 'off', '-W', '168']

    $.each(checked_nodes, function (index, node) {

        // console.log(index, node);

        if (node.iconSkin == 'testcase') {

            // var case_name = node.name;
            // var suite_name = node.getParentNode().name;
            // console.log(suite_name, case_name);
            get_suite_case_name(node);

            jetpack.write(argfile_path, argfile_data.join('\r\n'));

        }

    });

    var runargs = 'pybot.bat --argumentfile ' + argfile_path + ' --listener E:/workspace/ColoRide/app/plugin/rflistener/RFListener.py:' + randomtime + ' ' + $('#workspace_dir').text();// + ' > ' + runing_console_path;
    console.log(runargs);
    // exec(runargs);

    // exec(runargs, function (err, stdout, stderr) {
    //     if (err) throw err;
    //     else console.log(err, stdout, stderr);
    // });

    const ls = spawn('pybot.bat', ['--argumentfile', argfile_path, '--listener', 'E:/workspace/ColoRide/app/plugin/rflistener/RFListener.py:' + randomtime, $('#workspace_dir').text()]);

    ls.stdout.on('data', (data) => {
        console.log(iconv.decode(data, 'gbk'));
        $('#console_log').append(html_encode(iconv.decode(data, 'gbk')));

    });

    ls.stderr.on('data', (data) => {
        console.log(`stderr: ${data}`);
    });

    ls.on('close', (code) => {
        console.log(`子进程退出码：${code}`);
    });
}

var argfile_data = [];

function get_suite_case_name(node) {

    var case_name = [];
    var suite_name = [];

    $.each(node.getPath(), function (i, n) {

        case_name.push(n.name);
        suite_name.push(n.name);

    });

    suite_name.pop();

    argfile_data.push('--suite');
    argfile_data.push(suite_name.join("."));
    argfile_data.push('--test');
    argfile_data.push(case_name.join("."));

    console.log(case_name.join("."));
    console.log(suite_name.join("."));
}

function watch_running_log_file() {
    fs.watch(runing_log_path, 'utf8', (eventType, filename) => {
        console.log(`事件类型是: ${eventType}`);
        if (filename) {
            console.log(`提供的文件名: ${filename}`);
        } else {
            console.log('未提供文件名');
        }; fs.readFile(runing_log_path, 'utf8', (err, data) => {
            if (err) throw err;
            console.log(data);
            $('#running_log').html(html_encode(data));
        });
    });

    fs.watch(runing_console_path, 'utf8', (eventType, filename) => {
        console.log(`事件类型是: ${eventType}`);
        if (filename) {
            console.log(`提供的文件名: ${filename}`);
        } else {
            console.log('未提供文件名');
        }; fs.readFile(runing_console_path, 'utf8', (err, data) => {
            if (err) throw err;
            console.log(data);
            $('#console_log').html(html_encode(data));
        });
    });

}

function html_encode(str) {
    var s = "";
    if (str.length == 0) return "";
    s = str.replace(/&/g, ">");
    s = s.replace(/</g, "<");
    s = s.replace(/>/g, ">");
    s = s.replace(/ /g, " ");
    s = s.replace(/\'/g, "'");
    s = s.replace(/\"/g, "\"");
    s = s.replace(/\n/g, "
");
    return s;
}<commit_msg>优化 中文显示问题<commit_after>
const { app } = nodeRequire('electron').remote;
const path = nodeRequire("path");
const exec = nodeRequire('child_process').exec;
const spawn = nodeRequire('child_process').spawn;
const iconv = nodeRequire('iconv-lite');

var randomtime = 'RFEditor' + (new Date()).valueOf();

var temp_dir = path.join(app.getPath('temp'), randomtime);

var argfile_path = path.join(temp_dir, 'argfile.txt');

var runing_log_path = path.join(temp_dir, 'runing.txt');

jetpack.write(runing_log_path, '');

watch_running_log_file();

console.log(temp_dir);

function runTest() {

    $('#console_log').html('');
    $('#running_log').html('');

    var checked_nodes = zTree.getCheckedNodes(true);

    argfile_data = ['--outputdir', temp_dir, '-C', 'off', '-W', '168']

    $.each(checked_nodes, function (index, node) {

        // console.log(index, node);

        if (node.iconSkin == 'testcase') {

            // var case_name = node.name;
            // var suite_name = node.getParentNode().name;
            // console.log(suite_name, case_name);
            get_suite_case_name(node);

            jetpack.write(argfile_path, argfile_data.join('\r\n'));

        }

    });

    const runargs = spawn('pybot.bat', ['--argumentfile', argfile_path, '--listener', 'E:/workspace/ColoRide/app/plugin/rflistener/RFListener.py:' + randomtime, $('#workspace_dir').text()]);
    console.log(runargs);
    runargs.stdout.on('data', (data) => {
        console.log(iconv.decode(data, 'gbk'));
        $('#console_log').append(html_encode(iconv.decode(data, 'gbk')));

    });

    runargs.stderr.on('data', (data) => {
        console.log(`stderr: ${data}`);
    });

    runargs.on('close', (code) => {
        console.log(`子进程退出码：${code}`);
    });
}

var argfile_data = [];

function get_suite_case_name(node) {

    var case_name = [];
    var suite_name = [];

    $.each(node.getPath(), function (i, n) {

        case_name.push(n.name);
        suite_name.push(n.name);

    });

    suite_name.pop();

    argfile_data.push('--suite');
    argfile_data.push(suite_name.join("."));
    argfile_data.push('--test');
    argfile_data.push(case_name.join("."));

    console.log(case_name.join("."));
    console.log(suite_name.join("."));
}

function decodeUnicode(str) {
    str = str.replace(/\\/g, "%");
    return unescape(str);
}

function watch_running_log_file() {
    fs.watch(runing_log_path, 'utf8', (eventType, filename) => {
        console.log(`事件类型是: ${eventType}`);
        if (filename) {
            console.log(`提供的文件名: ${filename}`);
        } else {
            console.log('未提供文件名');
        }; fs.readFile(runing_log_path, 'utf8', (err, data) => {
            if (err) throw err;
            console.log(decodeUnicode(data));
            $('#running_log').html(html_encode(decodeUnicode(data)));
        });
    });

}

function html_encode(str) {
    var s = "";
    if (str.length == 0) return "";
    s = str.replace(/&/g, ">");
    s = s.replace(/</g, "<");
    s = s.replace(/>/g, ">");
    s = s.replace(/ /g, " ");
    s = s.replace(/\'/g, "'");
    s = s.replace(/\"/g, "\"");
    s = s.replace(/\n/g, "
");
    return s;
}<|endoftext|>


<commit_before>'use strict';

angular.module('sos.canvas', [])
    .controller('CanvasCtrl', ['$scope', '$log', '$injector', '$document', '$location', '$timeout',
                 function($scope, $log, $injector, $document, $location, $timeout) {

	$scope.wallDisplay = {
		width: 192,
		height: 320
	};

	$scope.stage = null;

	$scope.canvasDim = {
		width: 192,
		height: 320
	};
	$scope.offsetStyle = {
		left: 15,
		top: 0
	};

  $scope.urlParamConfig = {
    mode: 'modeSlowClap',
    wallDisplayMode: 'DEV',
    x: 15,
    y: 10
  };

	// mode metadata
	$scope.activeMode = null;
	$scope.modeModuleList = [ 'modeSlowClap',
                                  'modeTruchet',
                                  'modeSeascape',
                                  'modeEchoplex',
                                  'modeFlame',
                                  'modeBubbles',
                                  'modeCaustic',
                                  'modeCloudTen',
                                  'modeDisco',
                                  'modeHell',
                                  'modeRibbon',
                                  'modeStardust',
                                  'modeStorm',
                                  'modeTunnel',
                                  'modeVortex',
                                  'modeWorms',
                                  'modeNyan'
                                ];
  $scope.activeModeCounter = 0;

	$scope.loadedModes = {};
	$scope.kinectOverlay = true;

	// display metadata
	$scope.wallDisplayMode = "DEV";
	$scope.rotateForProduction = false;
	$scope.devModeInputGroupClass = "btn-primary active";
	$scope.prodModeInputGroupClass = "btn-primary";

	// debug object
	$scope.debugInfo = {

	};

	$scope.modeList = [];

	$scope.$watch('wallDisplayMode', function(newMode) {

		if(newMode == "DEV") {
			// if newMode is true, dev mode is enabled
			$log.info("DEV MODE");
			$scope.devModeInputGroupClass = "btn-primary active";
			$scope.prodModeInputGroupClass = "btn-default";
			angular.element($scope.canvasEl);
			$scope.rotateForProduction = false;
		} else {
			$log.info("PROD (WALL) MODE");
			$scope.devModeInputGroupClass = "btn-default";
			$scope.prodModeInputGroupClass = "btn-primary active";
			$scope.rotateForProduction = true;
		}

		$scope.updateLocationURLParam('wallDisplayMode', newMode);

	}, true);

  $scope.$watch('activeMode', function(activeMode) {
    $scope.updateLocationURLParam('mode', activeMode.id);
  });

  $scope.$watch('offsetStyle.left', function(newValue) {
    $scope.updateLocationURLParam('x', newValue);
  });

  $scope.$watch('offsetStyle.top', function(newValue) {
    $scope.updateLocationURLParam('y', newValue);
  });

	// keyboard bindings to move the canvas
	// in 1px increments
	keyboardJS.bind('w', function(e) {
		$scope.offsetStyle.top--;
		$scope.$digest();
	});
	keyboardJS.bind('s', function(e) {
		$scope.offsetStyle.top++;
		$scope.$digest();
	});
	keyboardJS.bind('a', function(e) {
		$scope.offsetStyle.left--;
		$scope.$digest();
	});
	keyboardJS.bind('d', function(e) {
		$scope.offsetStyle.left++;
		$scope.$digest();
	});

	keyboardJS.bind('n', function(n) {
    $scope.goToNextMode();
	});

	// binding to rotate display between DEV/PROD
	keyboardJS.bind('r', function(e) {
    // check if metaKey is active (to ignore CMD-R)
    if(!e.metaKey) {
		  $scope.toggleDisplayMode();
		  $scope.$digest();
		}
	});

	$scope.$on("error", function(err) {
		$log.warn("Registered error:", err);
	});

  $scope.postDebugInfo = function(name, value) {
    $scope.debugInfo[name] = value;
  };

	$scope.getWidthScaleFactor = function(origWidth) {
		return $scope.wallDisplay.width / origWidth;
	};

	$scope.getHeightScaleFactor = function(origHeight) {
		return $scope.wallDisplay.height / origHeight;
	};

	$scope.toggleDisplayMode = function() {
		if($scope.wallDisplayMode == "DEV") {
			$scope.wallDisplayMode = "PROD";
		} else {
			$scope.wallDisplayMode = "DEV";
		}

		// update config and url
	};

  $scope.updateLocationURLParam = function(paramName, paramValue) {
    $timeout(function() {
      $scope.urlParamConfig[paramName] = paramValue;
      $location.search($scope.urlParamConfig);
    });
  }

  $scope.toggleKinectOverlay = function() {

    var overlay = document.getElementById('kinect-overlay');
    overlay.hidden = $scope.kinectOverlay;
    $scope.kinectOverlay = !$scope.kinectOverlay;
  };

	$scope.goToNextMode = function() {
    $scope.activeModeCounter++;
    $scope.activeModeCounter %= $scope.modeModuleList.length;
    $scope.showMode($scope.modeModuleList[$scope.activeModeCounter]);
	};

	$scope.loadModules = function() {
		angular.forEach($scope.modeModuleList, function(value) {
			var mode = $injector.get(value);
			if(mode) {
				$scope.loadedModes[value] = mode;
			} else {
				$log.warn("Failed to load mode module: ", value);
			}

		});
	};

  // don't recreate contexts needlessly.
	$scope.threejs = {};
  $scope.threejs.renderer = new THREE.WebGLRenderer();
  $scope.threejs.renderer.setSize($scope.canvasDim.width, $scope.canvasDim.height);
  $scope.pixijs = {};
  $scope.pixijs.renderer = PIXI.autoDetectRenderer($scope.canvasDim.width, $scope.canvasDim.height, {backgroundColor : 0x1099bb, antialias: true});

	// initializers for two types of canvas
	$scope.createCanvas = function(rendererType) {

		$scope.canvasDiv = document.getElementById("canvas-stack");
		if(rendererType == "THREE") {
			$scope.canvasDiv.appendChild($scope.threejs.renderer.domElement);
		} else {
			$scope.canvasDiv.appendChild($scope.pixijs.renderer.view);
		}
	};

	$scope.clearCanvases = function() {
		angular.element($scope.canvasDiv).empty();
	};

	/* passing in null will function as clear canvas */
	$scope.showMode = function(modeName) {

		// deinit old module if it exists
		var oldMode = $scope.activeMode;
		if(oldMode) {
			$log.info("deinit:", oldMode.id);
			oldMode.deinit();
		}

		$scope.clearCanvases();

		// init new module and make active
		var mode = $scope.loadedModes[modeName];
		if(mode) {
			$scope.createCanvas(mode.rendererType);
			$log.info("init:", mode.id);
			mode.init($scope);
			$scope.activeMode = mode;
		} else {
  		$log.warn("Mode not found:", modeName);
		}
	};

	$scope.showKinectOverlay = function() {
		var mode = $injector.get('modeSkeletalFun');
		mode.init($scope);
	};

	$scope.setCanvasSize = function(width, height, canvas) {

		canvas.width = width;
		canvas.height = height;
	};

	$scope.init = function() {

    // get active mode param if it exists
    var urlParams = $location.search();
    $scope.urlParamConfig = angular.extend($scope.urlParamConfig, urlParams);

    // update all necessary parameters
    $scope.wallDisplayMode = $scope.urlParamConfig.wallDisplayMode;
    $scope.offsetStyle.top = $scope.urlParamConfig.y;
    $scope.offsetStyle.left = $scope.urlParamConfig.x;

		$scope.canvasDiv = document.getElementById("canvas-stack");
		$scope.loadModules();
		// set up default module
		$scope.showMode($scope.urlParamConfig.mode);
		$scope.showKinectOverlay();
	};

	// lastly, call init() to kick things off
	$scope.init();
}]);
<commit_msg>Fix spacing for canvas.js.<commit_after>'use strict';

angular.module('sos.canvas', []).controller('CanvasCtrl', ['$scope', '$log', '$injector', '$document', '$location', '$timeout', function($scope, $log, $injector, $document, $location, $timeout) {

  $scope.wallDisplay = {
    width: 192,
    height: 320
  };

  $scope.stage = null;

  $scope.canvasDim = {
    width: 192,
    height: 320
  };
  $scope.offsetStyle = {
    left: 15,
    top: 0
  };

  $scope.urlParamConfig = {
    mode: 'modeSlowClap',
    wallDisplayMode: 'DEV',
    x: 15,
    y: 10
  };

  // mode metadata
  $scope.activeMode = null;
  $scope.modeModuleList = [ 'modeSlowClap',
                            'modeTruchet',
                            'modeSeascape',
                            'modeEchoplex',
                            'modeFlame',
                            'modeBubbles',
                            'modeCaustic',
                            'modeCloudTen',
                            'modeDisco',
                            'modeHell',
                            'modeRibbon',
                            'modeStardust',
                            'modeStorm',
                            'modeTunnel',
                            'modeVortex',
                            'modeWorms',
                            'modeNyan'
                          ];
  $scope.activeModeCounter = 0;

  $scope.loadedModes = {};
  $scope.kinectOverlay = true;

  // display metadata
  $scope.wallDisplayMode = "DEV";
  $scope.rotateForProduction = false;
  $scope.devModeInputGroupClass = "btn-primary active";
  $scope.prodModeInputGroupClass = "btn-primary";

  // debug object
  $scope.debugInfo = {

  };

  $scope.modeList = [];

  $scope.$watch('wallDisplayMode', function(newMode) {

    if(newMode == "DEV") {
      // if newMode is true, dev mode is enabled
      $log.info("DEV MODE");
      $scope.devModeInputGroupClass = "btn-primary active";
      $scope.prodModeInputGroupClass = "btn-default";
      angular.element($scope.canvasEl);
      $scope.rotateForProduction = false;
    } else {
      $log.info("PROD (WALL) MODE");
      $scope.devModeInputGroupClass = "btn-default";
      $scope.prodModeInputGroupClass = "btn-primary active";
      $scope.rotateForProduction = true;
    }

    $scope.updateLocationURLParam('wallDisplayMode', newMode);

  }, true);

  $scope.$watch('activeMode', function(activeMode) {
    $scope.updateLocationURLParam('mode', activeMode.id);
  });

  $scope.$watch('offsetStyle.left', function(newValue) {
    $scope.updateLocationURLParam('x', newValue);
  });

  $scope.$watch('offsetStyle.top', function(newValue) {
    $scope.updateLocationURLParam('y', newValue);
  });

  // keyboard bindings to move the canvas
  // in 1px increments
  keyboardJS.bind('w', function(e) {
    $scope.offsetStyle.top--;
    $scope.$digest();
  });
  keyboardJS.bind('s', function(e) {
    $scope.offsetStyle.top++;
    $scope.$digest();
  });
  keyboardJS.bind('a', function(e) {
    $scope.offsetStyle.left--;
    $scope.$digest();
  });
  keyboardJS.bind('d', function(e) {
    $scope.offsetStyle.left++;
    $scope.$digest();
  });

  keyboardJS.bind('n', function(n) {
    $scope.goToNextMode();
  });

  // binding to rotate display between DEV/PROD
  keyboardJS.bind('r', function(e) {
    // check if metaKey is active (to ignore CMD-R)
    if(!e.metaKey) {
      $scope.toggleDisplayMode();
      $scope.$digest();
    }
  });

  $scope.$on("error", function(err) {
    $log.warn("Registered error:", err);
  });

  $scope.postDebugInfo = function(name, value) {
    $scope.debugInfo[name] = value;
  };

  $scope.getWidthScaleFactor = function(origWidth) {
    return $scope.wallDisplay.width / origWidth;
  };

  $scope.getHeightScaleFactor = function(origHeight) {
    return $scope.wallDisplay.height / origHeight;
  };

  $scope.toggleDisplayMode = function() {
    if($scope.wallDisplayMode == "DEV") {
      $scope.wallDisplayMode = "PROD";
    } else {
      $scope.wallDisplayMode = "DEV";
    }

    // update config and url
  };

  $scope.updateLocationURLParam = function(paramName, paramValue) {
    $timeout(function() {
      $scope.urlParamConfig[paramName] = paramValue;
      $location.search($scope.urlParamConfig);
    });
  };

  $scope.toggleKinectOverlay = function() {

    var overlay = document.getElementById('kinect-overlay');
    overlay.hidden = $scope.kinectOverlay;
    $scope.kinectOverlay = !$scope.kinectOverlay;
  };

  $scope.goToNextMode = function() {
    $scope.activeModeCounter++;
    $scope.activeModeCounter %= $scope.modeModuleList.length;
    $scope.showMode($scope.modeModuleList[$scope.activeModeCounter]);
  };

  $scope.loadModules = function() {
    angular.forEach($scope.modeModuleList, function(value) {
      var mode = $injector.get(value);
      if(mode) {
	$scope.loadedModes[value] = mode;
      } else {
	$log.warn("Failed to load mode module: ", value);
      }

    });
  };

  // don't recreate contexts needlessly.
  $scope.threejs = {};
  $scope.threejs.renderer = new THREE.WebGLRenderer();
  $scope.threejs.renderer.setSize($scope.canvasDim.width, $scope.canvasDim.height);
  $scope.pixijs = {};
  $scope.pixijs.renderer = PIXI.autoDetectRenderer($scope.canvasDim.width, $scope.canvasDim.height, {backgroundColor : 0x1099bb, antialias: true});

  // initializers for two types of canvas
  $scope.createCanvas = function(rendererType) {

    $scope.canvasDiv = document.getElementById("canvas-stack");
    if(rendererType == "THREE") {
      $scope.canvasDiv.appendChild($scope.threejs.renderer.domElement);
    } else {
      $scope.canvasDiv.appendChild($scope.pixijs.renderer.view);
    }
  };

  $scope.clearCanvases = function() {
    angular.element($scope.canvasDiv).empty();
  };

  /* passing in null will function as clear canvas */
  $scope.showMode = function(modeName) {

    // deinit old module if it exists
    var oldMode = $scope.activeMode;
    if(oldMode) {
      $log.info("deinit:", oldMode.id);
      oldMode.deinit();
    }

    $scope.clearCanvases();

    // init new module and make active
    var mode = $scope.loadedModes[modeName];
    if(mode) {
      $scope.createCanvas(mode.rendererType);
      $log.info("init:", mode.id);
      mode.init($scope);
      $scope.activeMode = mode;
    } else {
      $log.warn("Mode not found:", modeName);
    }
  };

  $scope.showKinectOverlay = function() {
    var mode = $injector.get('modeSkeletalFun');
    mode.init($scope);
  };

  $scope.disableKinectOverlay = function() {
    var mode = $injector.get('modeSkeletalFun');
    mode.deinit($scope);
  };

  $scope.setCanvasSize = function(width, height, canvas) {

    canvas.width = width;
    canvas.height = height;
  };

  $scope.init = function() {

    // get active mode param if it exists
    var urlParams = $location.search();
    $scope.urlParamConfig = angular.extend($scope.urlParamConfig, urlParams);

    // update all necessary parameters
    $scope.wallDisplayMode = $scope.urlParamConfig.wallDisplayMode;
    $scope.offsetStyle.top = $scope.urlParamConfig.y;
    $scope.offsetStyle.left = $scope.urlParamConfig.x;

    $scope.canvasDiv = document.getElementById("canvas-stack");
    $scope.loadModules();
    // set up default module
    $scope.showMode($scope.urlParamConfig.mode);

    $scope.showKinectOverlay();
  };

  // lastly, call init() to kick things off
  $scope.init();
}]);
<|endoftext|>


<commit_before>'use strict';

var Label = require('./label');
var LabelledOval = require('./labelledOval');
var Connector = require('./connector');
var ParseJSON = require('../helpers/parseJSON')

/**
 * Canvas The canvas object holds all of the drawing objects which are to be
 * 		rendered to the HTML5 Canvas. The Canvas correlates to the active "View" model.
 *
 * Todo: Refactor connectors
 */
module.exports = function Canvas() {

	var context = null;
	var canvas = null;
	var activeObjects = [];
	var height = 800;
	var width = 1200;
	var needRedraw = true;
	var state = 'stop';
	var label = new Label();

	/**
	 * initialize 	Configures the canvas representation using the html canvas element.
	 * @param  {canvas} canvas  pass in document.getElementById('my-canvas-name')
	 * @return {null}         currently returns nothing
	 *
	 * We could get the context and canvas by a document call here, but I'd prefer
	 * 		to keep this code ambivalent to the DOM namings etc.
	 *
	 * Todo: implement error handling on canvas load.
	 */
	this.initialize = function(c, viewName) {
		canvas = c;

		/*
		if(!this.canvas) {
			console.log('No HTML5 canvas was passed to the Canvas initialize function');
		}
		 */

		//temporary try block until I set up proper mocking for the html5 canvas object
		try {
			context = canvas.getContext('2d');
			width = canvas.width;
			height = canvas.height;
		}
		catch(e) {
			console.log(e);
		}

		activeObjects = [];
		needRedraw = true;
		label.initialize('Black', viewName, {x:0, y:0});
	};

	this.addDrawObject = function(obj) {
		activeObjects.push(obj);
	};

	/**
	 * draw() is the prime drawing logic of this app.
	 * It is a recursive function that deposits a request on the next AnimationFrame
	 * 		of the browser. When the canvas has been updated since last draw (needRedraw)
	 * 		it will clear the context (clearRect) and then call the draw function on
	 * 		each drawingObject (in activeObjects)
	 * At the moment it is coded to only call the callback on termination.
	 * @param  {Function} 		callback
	 * @return {null}           no return at this stage.
	 */
	var draw = function(callback) {

		if(state == 'stop') {
			callback(null, 'Stop request passed to canvas - draw cycle terminated');
			return;
		}
		if(state == 'loading') {
			console.log("canvas loading. Drawing paused. Checking at next draw cycle");
			window.requestAnimationFrame(draw.bind(this, callback));
		}

		//Check to see if image is unmodified before clearing/redrawing
		if(!needRedraw) {
			window.requestAnimationFrame(draw.bind(this));
		}

		//clearRect seems like an ugly implementation, hunt down alt.
		context.clearRect(0, 0, width, height);

		for (var o in activeObjects) {
			o.draw(context);
	    }

		/*this.activeObjects.forEach(function (o, index) {
			o.draw(this.context);
		});*/

		/*
		//"of" not functioning for some reason.
		for(let o of this.activeObjects) {
			o.draw(this.context);
		}*/

		needRedraw = false;

		window.requestAnimationFrame(draw.bind(this, callback));	  //recode to pass in callback
	};

	this.run = function() {
		state = 'run';	//Need to create an async implementation of this

		window.requestAnimationFrame(draw.bind(this));   //recode to pass in callback
	};

	this.stop = function() {
		state = 'stop';
	};

	this.removeDrawObject = function(drawObject) {
		var ix = activeObjects.indexOf(drawObject);
		if(ix > -1) {
			activeObjects.splice(ix, 1);
		}
	};

	//how to track whether a redraw is necessary:
	// opt1: force  all updates to pass through the canvas draw object, have a simple flag.
	//	upside - keeps drawing logic segregated from business logic. Simple flag to update and check
	//	downside - passes all updates through this function. Has the potential to inhibit more complex update functions.
	//		seperates view logic too far from controlling entity.
	// opt2: tie drawing objects to their appropriate
	//
	// Update currently functions by replacing the object
	// 		Alt: call an update on the drawObject
	this.updateDrawObject = function(drawObject) {
		var ix = activeObjects.indexOf(drawObject);
		activeObjects[ix] = drawObject;
	};

	this.getState = function() {
		return state;
	};

	this.getDimensions = function() {
		return {h:height, w:width};
	};

	//Need to refactor for aSync
	this.clear = function() {
		this.stop();
		context.clearRect(0, 0, width, height);
		label = new Label();
		activeObjects = null;
	};

	// Note: current load an save work based on each drawing object being JSONified
	//		a more efficient approach would be to retain only the most relevant info.
	//		Namely: location, text, colours etc.
	//		This would then allow the function to load previously undrawn views.
	//
	// Todo: Refactor Load and Save functions

	/**
	 * Load takes a JSON object containing the definition of all the canvas elements
	 * @param  {JSON} canvasJSON 	JSON representation of a canvas object
	 * @return {object} this        Return this Canvas object
	 */
	this.load = function(objects, title, callback) {
		this.clear();

		label.text = title;
		for(var o in objects) {
			var l = new labelledOval();

			//need to add ID to labelledOval
			l.initialize(o.title, o.colour, o.dimensions);
			//style?
			this.addDrawObject(l);
		}

		//this.run();

		return this;
	};

	this.save = function() {
		return {
			label:JSON.stringify(label),
			activeObjects:JSON.stringify(activeObjects)
		};
	};

	this.export = function() {
		console.log("Canvas.export() has not yet been implemented");
	};
};

//Experimentation with ES6 class implementation
/*

'use strict';

module.exports = function() {};

class Canvas {

	constructor() {
		this.context = null;
		this.activeObjects = [];
		this.height = 800;
		this.width = 1200;
		this.needRedraw =true;
	}

	initialize(ctx, width, height) {
		this.context = ctx;
		this.activeObjects = [];
		this.needRedraw = true;
		this.width = width;
		this.height = height;
	}

	addDrawObject(obj) {
		this.activeObjects.push(obj);
	}

	draw() {
		if(!this.needRedraw) { return; }

		//This seems like an ugly implementation, hunt down alt.
		this.context.clearRect(0, 0, this.width, this. height);
		for(var o of this.activeObjects) {
			o.draw(this.context);
		}
		this.needRedraw = false;
	}

	removeDrawObject(drawObject) {
		var ix = this.activeObjects.indexOf(drawObject);
		if(ix > -1) {
			this.activeObjects.splice(ix, 1);
		}
	}

	//how to track whether a redraw is necessary:
	// opt1: force  all updates to pass through the canvas draw object, have a simple flag.
	//	upside - keeps drawing logic segregated from business logic. Simple flag to update and check
	//	downside - passes all updates through this function. Has the potential to inhibit more complex update functions.
	//		seperates view logic too far from controlling entity.
	// opt2: tie drawing objects to their appropriate
	//
	// Update currently functions by replacing the object
	// 		Alt: call an update on the drawObject
	updateDrawObject(drawObject) {
		var ix = this.activeObjects.indexOf(drawObject);
		this.activeObjects[ix] = drawObject;
	}
}

module.exports.Canvas = Canvas;*/

//alt module.exports default Canvas?<commit_msg>minor change<commit_after>'use strict';

var Label = require('./label');
var LabelledOval = require('./labelledOval');
var Connector = require('./connector');
var ParseJSON = require('../helpers/parseJSON')

/**
 * Canvas The canvas object holds all of the drawing objects which are to be
 * 		rendered to the HTML5 Canvas. The Canvas correlates to the active "View" model.
 *
 * Todo: Refactor connectors
 */
module.exports = function Canvas() {

	var context = null;
	var canvas = null;
	var activeObjects = [];
	var height = 800;
	var width = 1200;
	var needRedraw = true;
	var state = 'stop';
	var label = new Label();

	/**
	 * initialize 	Configures the canvas representation using the html canvas element.
	 * @param  {canvas} canvas  pass in document.getElementById('my-canvas-name')
	 * @return {null}         currently returns nothing
	 *
	 * We could get the context and canvas by a document call here, but I'd prefer
	 * 		to keep this code ambivalent to the DOM namings etc.
	 *
	 * Todo: implement error handling on canvas load.
	 */
	this.initialize = function(c, viewName) {
		canvas = c;

		/*
		if(!this.canvas) {
			console.log('No HTML5 canvas was passed to the Canvas initialize function');
		}
		 */

		//temporary try block until I set up proper mocking for the html5 canvas object
		try {
			context = canvas.getContext('2d');
			width = canvas.width;
			height = canvas.height;
		}
		catch(e) {
			console.log(e);
		}

		activeObjects = [];
		needRedraw = true;
		label.initialize('Black', viewName, {x:0, y:0});
	};

	this.addDrawObject = function(obj) {
		activeObjects.push(obj);
	};

	/**
	 * draw() is the prime drawing logic of this app.
	 * It is a recursive function that deposits a request on the next AnimationFrame
	 * 		of the browser. When the canvas has been updated since last draw (needRedraw)
	 * 		it will clear the context (clearRect) and then call the draw function on
	 * 		each drawingObject (in activeObjects)
	 * At the moment it is coded to only call the callback on termination.
	 * @param  {Function} 		callback
	 * @return {null}           no return at this stage.
	 */
	var draw = function(callback) {

		if(state == 'stop') {
			callback(null, 'Stop request passed to canvas - draw cycle terminated');
			return;
		}
		if(state == 'loading') {
			console.log("canvas loading. Drawing paused. Checking at next draw cycle");
			window.requestAnimationFrame(draw.bind(this, callback));
		}

		//Check to see if image is unmodified before clearing/redrawing
		if(!needRedraw) {
			window.requestAnimationFrame(draw.bind(this));
		}

		//clearRect seems like an ugly implementation, hunt down alt.
		context.clearRect(0, 0, width, height);

		for (var o in activeObjects) {
			o.draw(context);
	    }

		/*this.activeObjects.forEach(function (o, index) {
			o.draw(this.context);
		});*/

		/*
		//"of" not functioning for some reason.
		for(let o of this.activeObjects) {
			o.draw(this.context);
		}*/

		needRedraw = false;

		window.requestAnimationFrame(draw.bind(this, callback));	  //recode to pass in callback
	};

	this.run = function() {
		state = 'run';	//Need to create an async implementation of this

		window.requestAnimationFrame(draw.bind(this));   //recode to pass in callback
	};

	this.stop = function() {
		state = 'stop';
	};

	this.removeDrawObject = function(drawObject) {
		var ix = activeObjects.indexOf(drawObject);
		if(ix > -1) {
			activeObjects.splice(ix, 1);
		}
	};

	//how to track whether a redraw is necessary:
	// opt1: force  all updates to pass through the canvas draw object, have a simple flag.
	//	upside - keeps drawing logic segregated from business logic. Simple flag to update and check
	//	downside - passes all updates through this function. Has the potential to inhibit more complex update functions.
	//		seperates view logic too far from controlling entity.
	// opt2: tie drawing objects to their appropriate
	//
	// Update currently functions by replacing the object
	// 		Alt: call an update on the drawObject
	this.updateDrawObject = function(drawObject) {
		var ix = activeObjects.indexOf(drawObject);
		activeObjects[ix] = drawObject;
	};

	this.getState = function() {
		return state;
	};

	this.getDimensions = function() {
		return {h:height, w:width};
	};

	//Need to refactor for aSync
	this.clear = function() {
		this.stop();
		context.clearRect(0, 0, width, height);
		label = new Label();
		activeObjects = null;
	};

	// Note: current load an save work based on each drawing object being JSONified
	//		a more efficient approach would be to retain only the most relevant info.
	//		Namely: location, text, colours etc.
	//		This would then allow the function to load previously undrawn views.
	//
	// Todo: Refactor Load and Save functions

	/**
	 * Load takes a JSON object containing the definition of all the canvas elements
	 * @param  {JSON} canvasJSON 	JSON representation of a canvas object
	 * @return {object} this        Return this Canvas object
	 */
	this.load = function(objects, title, callback) {
		this.clear();

		label.text = title;
		for(var o in objects) {
			var l = new labelledOval();

			//need to add ID to labelledOval
			l.initialize(o.title, o.colour, o.dimensions);
			//style?
			this.addDrawObject(l);
		}

		callback();
		//this.run();

		return this;
	};

	//Refactor
	this.save = function() {
		return {
			label:JSON.stringify(label),
			activeObjects:JSON.stringify(activeObjects)
		};
	};

	this.export = function() {
		console.log("Canvas.export() has not yet been implemented");
	};
};

//Experimentation with ES6 class implementation
/*

'use strict';

module.exports = function() {};

class Canvas {

	constructor() {
		this.context = null;
		this.activeObjects = [];
		this.height = 800;
		this.width = 1200;
		this.needRedraw =true;
	}

	initialize(ctx, width, height) {
		this.context = ctx;
		this.activeObjects = [];
		this.needRedraw = true;
		this.width = width;
		this.height = height;
	}

	addDrawObject(obj) {
		this.activeObjects.push(obj);
	}

	draw() {
		if(!this.needRedraw) { return; }

		//This seems like an ugly implementation, hunt down alt.
		this.context.clearRect(0, 0, this.width, this. height);
		for(var o of this.activeObjects) {
			o.draw(this.context);
		}
		this.needRedraw = false;
	}

	removeDrawObject(drawObject) {
		var ix = this.activeObjects.indexOf(drawObject);
		if(ix > -1) {
			this.activeObjects.splice(ix, 1);
		}
	}

	//how to track whether a redraw is necessary:
	// opt1: force  all updates to pass through the canvas draw object, have a simple flag.
	//	upside - keeps drawing logic segregated from business logic. Simple flag to update and check
	//	downside - passes all updates through this function. Has the potential to inhibit more complex update functions.
	//		seperates view logic too far from controlling entity.
	// opt2: tie drawing objects to their appropriate
	//
	// Update currently functions by replacing the object
	// 		Alt: call an update on the drawObject
	updateDrawObject(drawObject) {
		var ix = this.activeObjects.indexOf(drawObject);
		this.activeObjects[ix] = drawObject;
	}
}

module.exports.Canvas = Canvas;*/

//alt module.exports default Canvas?<|endoftext|>


<commit_before>'use strict';

angular.module('doc.client', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/client', {
    templateUrl: 'client/client.html',
    controller: 'ClientCtrl'
  });
  $routeProvider.when('/', {
    templateUrl: 'client/client.html',
    controller: 'ClientCtrl'
  });
}])

.controller('ClientCtrl', ["$scope", "queue", "search", "playback", function($scope, queue, search, playback) {

	/* Definitions */

	$scope.queue = [];
	$scope.currentlyPlaying = null;
	$scope.chk = {
		recent: false,
		related: false,
		relatedToRecent: false
	}
	$scope.showControls = false;
	$scope.playbackState = false;
	$scope.magicModeState = false;
	$scope.playbackStateIcon = "fa fa-play fa-2x";
	$scope.playbackStateMessage = "Resume Playback";
	$scope.playbackMaxLengthState = true;
	$scope.magicModeState = false;

	/* Queue */

	$scope.updateQueue = function (){
		queue.get(function(response){
			$scope.queue = response.queue;
			$scope.currentlyPlaying = response.current;
		});
	}

	/* Skip Current Song */
	$scope.skipSong = function(){
		playback.skip();
	}

	/* Related */

	$scope.relatedCheckboxClicked = function(){
		playback.setRelated($scope.chk.related, function(resp){
			$scope.chk.related = resp.state;
			$scope.updateMagicModeState();
		});
	}

	$scope.updateRelatedCheckbox = function(){
		playback.getRelated(function(resp){
			$scope.chk.related = resp.state;
		})
	}

	$scope.clearRecent = function(){
		playback.clearRecentList();
	}

	/* Related To Recent */

	$scope.relatedToRecentCheckboxClicked = function(){
		playback.setRelatedToRecent($scope.chk.relatedToRecent, function(resp){
			$scope.chk.relatedToRecent = resp.state;
			$scope.updateMagicModeState();
		});
	}

	$scope.updateRelatedToRecentCheckbox = function(){
		playback.getRelatedToRecent(function(resp){
			$scope.chk.relatedToRecent = resp.state;
		});
	};

	/* Recent */

	$scope.recentCheckboxClicked = function(){
		playback.setRecent($scope.chk.recent, function(resp){
			$scope.recentCheckbox = resp.state;
		});
	};

	$scope.updateRecentCheckbox = function(){
		playback.getRecent(function(resp){
			$scope.chk.recent = resp.state;
		});
	};

	/* Playback State */

	$scope.playbackStateButtonClicked = function(){
		$scope.playbackState = !$scope.playbackState
		playback.setState($scope.playbackState, function(resp){
			$scope.playbackState = resp.state;

			if($scope.playbackState){
				$scope.playbackStateIcon = "fa fa-pause fa-2x";
				$scope.playbackStateMessage = "Pause Playback";
			}
			else{
				$scope.playbackStateIcon = "fa fa-play fa-2x";
				$scope.playbackStateMessage = "Resume Playback";
			}
		});
	};

	$scope.updatePlaybackState = function(){
		if($scope.showControls){
			playback.getState(function(resp){
				$scope.playbackState = resp.state;

				if($scope.playbackState){
					$scope.playbackStateIcon = "fa fa-pause fa-2x";
					$scope.playbackStateMessage = "Pause Playback fa-2x";
				}
				else{
					$scope.playbackStateIcon = "fa fa-play";
					$scope.playbackStateMessage = "Resume Playback";
				}
			})
		}
	};

	/* Search Song */

	$scope.searchSong = function(){
		search($scope.url, function(results){
			$scope.searchResults = results;
		})
	};

	$scope.requestSong = function(ytid){
		for(var i=0; i < $scope.searchResults.length; i++){
			if($scope.searchResults[i].yt === ytid){
				var song = $scope.searchResults[i];
				queue.add({
					url: song.url,
					yt: song.yt,
					title: song.title,
					uploader: song.uploader,
					description: song.description,
					thumbnail: song.thumbnail
				}, function(res){
					updateQueue();
				});
				alert("Song Requested\n" + song.title);
				break;
			}
		}
	};

	/* Hide/Show Controls */

	$scope.toggleControls = function(){
		$scope.showControls = !$scope.showControls;
	};

	/* Magic Mode */
	$scope.toggleMagicMode = function(){
		$scope.chk.related = !$scope.chk.related;
		$scope.chk.relatedToRecent = !$scope.chk.relatedToRecent;
		$scope.relatedCheckboxClicked();
		$scope.relatedToRecentCheckboxClicked();
		$scope.magicModeState = !$scope.magicModeState;
	}

	$scope.updateMagicModeState = function(){
		$scope.magicModeState =($scope.chk.related && $scope.chk.relatedToRecent);
	}

	/* Easter Eggs */
	$scope.easterEgg = function(){
		alert("It looked unbalanced without the one on the left...");
	}

	var egg = new Egg("up,up,down,down,left,right,left,right,b,a", function() {
		playback.toggleMaxLengthState(function(resp){
			$scope.playbackMaxLengthState = resp.state;
		});
	}).listen();

	$scope.updateMaxLength = function(){
		playback.getMaxLengthState(function(resp){
			$scope.playbackMaxLengthState = resp.state;
		});
	};

	/* UI REST Data Update Timer */

	$scope.restUpdate = function(){
		$scope.updateQueue();
		$scope.updateRelatedCheckbox();
		$scope.updateRelatedToRecentCheckbox();
		$scope.updateRecentCheckbox();
		$scope.updatePlaybackState();
		$scope.updateMaxLength();
		$scope.updateMagicModeState();
	};

	$scope.restUpdate();
	$scope.updateTimer = setInterval($scope.restUpdate, 10000);

}]);
<commit_msg>fixes show controlls play/pause issue<commit_after>'use strict';

angular.module('doc.client', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/client', {
    templateUrl: 'client/client.html',
    controller: 'ClientCtrl'
  });
  $routeProvider.when('/', {
    templateUrl: 'client/client.html',
    controller: 'ClientCtrl'
  });
}])

.controller('ClientCtrl', ["$scope", "queue", "search", "playback", function($scope, queue, search, playback) {

	/* Definitions */

	$scope.queue = [];
	$scope.currentlyPlaying = null;
	$scope.chk = {
		recent: false,
		related: false,
		relatedToRecent: false
	}
	$scope.showControls = false;
	$scope.playbackState = false;
	$scope.magicModeState = false;
	$scope.playbackStateIcon = "fa fa-play fa-2x";
	$scope.playbackStateMessage = "Resume Playback";
	$scope.playbackMaxLengthState = true;
	$scope.magicModeState = false;

	/* Queue */

	$scope.updateQueue = function (){
		queue.get(function(response){
			$scope.queue = response.queue;
			$scope.currentlyPlaying = response.current;
		});
	}

	/* Skip Current Song */
	$scope.skipSong = function(){
		playback.skip();
	}

	/* Related */

	$scope.relatedCheckboxClicked = function(){
		playback.setRelated($scope.chk.related, function(resp){
			$scope.chk.related = resp.state;
			$scope.updateMagicModeState();
		});
	}

	$scope.updateRelatedCheckbox = function(){
		playback.getRelated(function(resp){
			$scope.chk.related = resp.state;
		})
	}

	$scope.clearRecent = function(){
		playback.clearRecentList();
	}

	/* Related To Recent */

	$scope.relatedToRecentCheckboxClicked = function(){
		playback.setRelatedToRecent($scope.chk.relatedToRecent, function(resp){
			$scope.chk.relatedToRecent = resp.state;
			$scope.updateMagicModeState();
		});
	}

	$scope.updateRelatedToRecentCheckbox = function(){
		playback.getRelatedToRecent(function(resp){
			$scope.chk.relatedToRecent = resp.state;
		});
	};

	/* Recent */

	$scope.recentCheckboxClicked = function(){
		playback.setRecent($scope.chk.recent, function(resp){
			$scope.recentCheckbox = resp.state;
		});
	};

	$scope.updateRecentCheckbox = function(){
		playback.getRecent(function(resp){
			$scope.chk.recent = resp.state;
		});
	};

	/* Playback State */

	$scope.playbackStateButtonClicked = function(){
		$scope.playbackState = !$scope.playbackState
		playback.setState($scope.playbackState, function(resp){
			$scope.playbackState = resp.state;

			if($scope.playbackState){
				$scope.playbackStateIcon = "fa fa-pause fa-2x";
				$scope.playbackStateMessage = "Pause Playback";
			}
			else{
				$scope.playbackStateIcon = "fa fa-play fa-2x";
				$scope.playbackStateMessage = "Resume Playback";
			}
		});
	};

	$scope.updatePlaybackState = function(){
		playback.getState(function(resp){
			$scope.playbackState = resp.state;

			if($scope.playbackState){
				$scope.playbackStateIcon = "fa fa-pause fa-2x";
				$scope.playbackStateMessage = "Pause Playback fa-2x";
			}
			else{
				$scope.playbackStateIcon = "fa fa-play";
				$scope.playbackStateMessage = "Resume Playback";
			}
		})
	};

	/* Search Song */

	$scope.searchSong = function(){
		search($scope.url, function(results){
			$scope.searchResults = results;
		})
	};

	$scope.requestSong = function(ytid){
		for(var i=0; i < $scope.searchResults.length; i++){
			if($scope.searchResults[i].yt === ytid){
				var song = $scope.searchResults[i];
				queue.add({
					url: song.url,
					yt: song.yt,
					title: song.title,
					uploader: song.uploader,
					description: song.description,
					thumbnail: song.thumbnail
				}, function(res){
					updateQueue();
				});
				alert("Song Requested\n" + song.title);
				break;
			}
		}
	};

	/* Hide/Show Controls */

	$scope.toggleControls = function(){
		$scope.showControls = !$scope.showControls;
	};

	/* Magic Mode */
	$scope.toggleMagicMode = function(){
		$scope.chk.related = !$scope.chk.related;
		$scope.chk.relatedToRecent = !$scope.chk.relatedToRecent;
		$scope.relatedCheckboxClicked();
		$scope.relatedToRecentCheckboxClicked();
		$scope.magicModeState = !$scope.magicModeState;
	}

	$scope.updateMagicModeState = function(){
		$scope.magicModeState =($scope.chk.related && $scope.chk.relatedToRecent);
	}

	/* Easter Eggs */
	$scope.easterEgg = function(){
		alert("It looked unbalanced without the one on the left...");
	}

	var egg = new Egg("up,up,down,down,left,right,left,right,b,a", function() {
		playback.toggleMaxLengthState(function(resp){
			$scope.playbackMaxLengthState = resp.state;
		});
	}).listen();

	$scope.updateMaxLength = function(){
		playback.getMaxLengthState(function(resp){
			$scope.playbackMaxLengthState = resp.state;
		});
	};

	/* UI REST Data Update Timer */

	$scope.restUpdate = function(){
		$scope.updateQueue();
		$scope.updateRelatedCheckbox();
		$scope.updateRelatedToRecentCheckbox();
		$scope.updateRecentCheckbox();
		$scope.updatePlaybackState();
		$scope.updateMaxLength();
		$scope.updateMagicModeState();
	};

	$scope.restUpdate();
	$scope.updateTimer = setInterval($scope.restUpdate, 10000);

}]);
<|endoftext|>


<commit_before>define([], function () {
    var config = {};

    config.version = '0.1.1';

    config.API_ROOT_URL = 'http://dev.keeleressursid.ee/';
    config.API_AUTH_URL = config.API_ROOT_URL+'api/auth/login/';
    config.API_URL = config.API_ROOT_URL + 'api/v1/';

    config.user = {
        roles: ['regular', 'admin']
    };

    config.project = {
        userRoles: ['editor', 'viewer']
    };

    config.resource_type = {
        split_types: ['NONE', 'LINE']
    };
    config.workflow_statuses = ['INIT', 'RUNNING', 'FINISHED', 'ERROR', 'CANCELLED'];
    config.hearbeat_interval = 3600;

    return config;

});<commit_msg>Uus versioon<commit_after>define([], function() {
	var config = {};

	config.version = '0.2.0';

	config.API_ROOT_URL = 'http://dev.keeleressursid.ee/';
	config.API_AUTH_URL = config.API_ROOT_URL + 'api/auth/login/';
	config.API_URL = config.API_ROOT_URL + 'api/v1/';

	config.user = {
		roles : [ 'regular', 'admin' ]
	};

	config.project = {
		userRoles : [ 'editor', 'viewer' ]
	};

	config.resource_type = {
		split_types : [ 'NONE', 'LINE' ]
	};
	config.workflow_statuses = [ 'INIT', 'RUNNING', 'FINISHED', 'ERROR',
			'CANCELLED' ];
	config.hearbeat_interval = 3600;

	return config;

});<|endoftext|>


<commit_before>import React, { Component } from "react";
import Data from "./../services/github_api";
import _ from 'lodash';
import Repositories from "./../components/repositories";
import { DropdownButton, ButtonToolbar, MenuItem } from 'react-bootstrap';
//import {Loading} from "./../components/loading"

const cursorStyle = {
	cursor: 'pointer'
}

const bodyStyle = {
	margin: "20px 50px 20px 50px"
}

class App extends Component {
	constructor(props) {
		super(props);
		this.state = {
			info: [],
		}
		this.gotoUrl = this.gotoUrl.bind(this);
	}

	componentDidMount() {
		Data("").then(res => {
			this.setState({ info: res.data.items })
		})
	}

	gotoUrl(url) {
		console.log("in goto url");
		window.open(url);
	}

	render() {
		const that = this;
		return this.state.info.length ?

Filters

						<ButtonToolbar>
							<DropdownButton title="Languages" id="dropdown-size-medium">
								<MenuItem eventKey="1">JavaScript</MenuItem>
								<MenuItem eventKey="2">Ruby</MenuItem>
								<MenuItem eventKey="3">Python</MenuItem>
							</DropdownButton>
						</ButtonToolbar>

 {this.state.info.map(function (item, i) {
						return (

								<Repositories key={i} name={item.full_name} description={item.description} language={item.language} stars={item.stargazers_count} forks={item.forks} avatar={item.owner.avatar_url} />

						)
					})
					}

			:
			(

			)
	}
}

module.exports = App;<commit_msg>filter by language feature<commit_after>import React, { Component } from "react";
import Data from "./../services/github_api";
import _ from 'lodash';
import Repositories from "./../components/repositories";
import { DropdownButton, ButtonToolbar, MenuItem } from 'react-bootstrap';
//import {Loading} from "./../components/loading"

const cursorStyle = {
	cursor: 'pointer'
}

const bodyStyle = {
	margin: "20px 50px 20px 50px"
}

class App extends Component {
	constructor(props) {
		super(props);
		this.state = {
			info: [],
			lang_title : "Select",
		}
		this.gotoUrl = this.gotoUrl.bind(this);
		this.handleSelect = this.handleSelect.bind(this);
	}

	componentDidMount() {
		Data("").then(res => {
			this.setState({ info: res.data.items })
		})
	}

	gotoUrl(url) {
		console.log("in goto url");
		window.open(url);
	}

	handleSelect(lang) {
		console.log("in handleSelect");
		this.setState({lang_title: lang});
		if(lang=="Select"){
			Data("").then(res => {
				this.setState({ info: res.data.items })
			})
		}
		else{
			Data("language:"+lang).then(res => {
				this.setState({ info: res.data.items })
			})
		}
	}

	render() {
		const that = this;
		return this.state.info.length ?

Filters

Languages

						<ButtonToolbar>
							<DropdownButton title={this.state.lang_title} id="dropdown-languages">
								<MenuItem eventKey="1" onSelect={_.partial(that.handleSelect, "Select")}>Select</MenuItem>
								<MenuItem eventKey="1" onSelect={_.partial(that.handleSelect, "javaScript")}>JavaScript</MenuItem>
								<MenuItem eventKey="2" onSelect={_.partial(that.handleSelect, "ruby")}>Ruby</MenuItem>
								<MenuItem eventKey="3" onSelect={_.partial(that.handleSelect, "python")}>Python</MenuItem>
							</DropdownButton>
						</ButtonToolbar>

 {this.state.info.map(function (item, i) {
						return (

								<Repositories key={i} name={item.full_name} description={item.description} language={item.language} stars={item.stargazers_count} forks={item.forks} avatar={item.owner.avatar_url} />

						)
					})
					}

			:
			(

			)
	}
}

module.exports = App;<|endoftext|>