Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions jstests/tests/home/mock_remoteappapi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
define(function (require) {
"use strict";
var MockApi = function () {
this.available_applications_info = function () {
return [{
image: {
name: "app1",
ui_name: "Application 1",
icon_128: "",
description: "description",
policy: {
allow_home: true,
volume_source: "",
volume_target: "",
volume_mode: ""
},
configurables: [
"resolution"
]
},
mapping_id: "12345"
},
{
image: {
name: "app2",
ui_name: "Application 2",
icon_128: "",
description: "description",
policy: {
allow_home: true,
volume_source: "",
volume_target: "",
volume_mode: ""
},
configurables: []
},
mapping_id: "67890"
}];
};
};

return {
MockApi: MockApi
};
});
25 changes: 25 additions & 0 deletions jstests/tests/home/test_configurables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
define(function (require) {
"use strict";
var configurables = require("home/configurables");

QUnit.module("home.configurables");
QUnit.test("instantiation", function (assert) {
var resolution_class = configurables.from_tag("resolution");
var resolution = new resolution_class();
assert.equal(resolution.tag, "resolution");
assert.equal(resolution.resolution, "Window");

resolution.resolution = "1024x768";
assert.equal(resolution.as_config_dict().resolution, "1024x768");
});

QUnit.test("view", function (assert) {
var resolution_class = configurables.from_tag("resolution");
var resolution = new resolution_class();

var view = resolution.view();
assert.notEqual(view.find("select"), null);
assert.equal(view.find("option").length,
resolution.resolution_options.length);
});
});
19 changes: 9 additions & 10 deletions jstests/tests/home/test_models.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
define(function (require) {
"use strict";
var models = require("home/models");

var MockApi = function () {
this.available_applications_info = function() {
return [{}, {}];
};
};
var mock_api = require("../../../../../jstests/tests/home/mock_remoteappapi");

QUnit.module("home.models");
QUnit.test("instantiation", function (assert) {
var mock_api = new MockApi();
var model = new models.ApplicationListModel(mock_api);
assert.equal(model.data.length, 0);
var api = new mock_api.MockApi();
var model = new models.ApplicationListModel(api);
assert.equal(model.app_data.length, 0);
model.update().done(function() {
assert.equal(model.data.length, 2);
assert.equal(model.app_data.length, 2);
assert.equal(model.app_data[0].image.configurables[0], "resolution");
assert.notEqual(model.configurables[0].resolution, null);
assert.equal(model.configurables[0].resolution.resolution, "Window");
});
});
});

37 changes: 10 additions & 27 deletions jstests/tests/home/test_views.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,26 @@ define(function (require) {
"use strict";
var models = require("home/models");
var views = require("home/views");
var mock_api = require("../../../../../jstests/tests/home/mock_remoteappapi");
var $ = require("jquery");

var MockApi = function () {
this.available_applications_info = function() {
return [
{
image : {
ui_name : "foo",
policy : {
allow_home: true
}
}
},
{
image: {
ui_name : "bar",
policy : {
allow_home: true
}
}
}];
};
};

QUnit.module("home.views");
QUnit.test("rendering", function (assert) {
var mock_api = new MockApi();
var model = new models.ApplicationListModel(mock_api);
var api = new mock_api.MockApi();
var model = new models.ApplicationListModel(api);
var view = new views.ApplicationListView(model);
model.update()
.done(function() { view.render(); } )
.done(function() {
var applist = $("#applist");
assert.equal(applist.children().length, 2);
assert.equal($("#applist > div:nth-child(1) > div > h4").text(), "foo");
assert.equal($("#applist > div:nth-child(2) > div > h4").text(), "bar");
assert.equal($("#applist > div:nth-child(1) > div > h4").text(), "Application 1");
assert.equal($("#applist > div:nth-child(2) > div > h4").text(), "Application 2");
})
.done(function() {
model.app_data[0].image.ui_name = "Hello";
view.update_entry(0);
assert.equal($("#applist > div:nth-child(1) > div > h4").text(), "Hello");
});

});
});
1 change: 1 addition & 0 deletions jstests/testsuite.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
});

require([
"tests/home/test_configurables.js",
"tests/home/test_models.js",
"tests/home/test_views.js",
"tests/test_remoteappapi.js",
Expand Down
88 changes: 88 additions & 0 deletions remoteappmanager/static/js/home/configurables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
define(["jquery"], function($) {
"use strict";

var ResolutionModel = function () {
// Model for the resolution configurable.
var self = this;
this.resolution = "Window";
this.resolution_options = ["Window", "1920x1080", "1280x1024", "1280x800", "1024x768"];

self.view = function () {
// Creates the View to add to the application entry.
var opts = "";
for (var i = 0; i < self.resolution_options.length; ++i) {
var opt = self.resolution_options[i];
opts += "<option value='" + opt + "'>" + opt + "</option>";
}
var widget = $("<p>" +
"Resolution: " +
"<select>" +
opts +
"</select></p>"
);

widget.find("select").change(function() {
if (this.selectedIndex) {
self.resolution = this.options[this.selectedIndex].value;
}
});

return widget;

};
};

ResolutionModel.prototype.tag = "resolution";

ResolutionModel.prototype.as_config_dict = function() {
// Returns the configuration dict to hand over to the API request.
// e.g.
// {
// "resolution" : "1024x768"
// }
// The returned dictionary must be added to the configurable
// parameter under the key given by the tag member.
var resolution = this.resolution;

if (resolution === 'Window') {
resolution = this._viewport_resolution();
}

return {
"resolution": resolution
};
};

ResolutionModel.prototype._viewport_resolution = function () {
// Returns the current viewport resolution as a "WxH" string
var e = window, a = 'inner';
if ( !( 'innerWidth' in window ) ) {
a = 'client';
e = document.documentElement || document.body;
}
return e[ a+'Width' ]+"x"+e[ a+'Height' ];
};

// Define all your configurables here.
var configurables = {
ResolutionModel: ResolutionModel
};

var from_tag = function (tag) {
// Given a tag, lookup the appropriate configurable and
// return it. If the tag matches no configurable, returns null
for (var conf in configurables) {
if (configurables[conf].prototype.tag === tag) {
return configurables[conf];
}
}
return null;
};

var ns = {
from_tag: from_tag
};

return $.extend(ns, configurables);

});
22 changes: 17 additions & 5 deletions remoteappmanager/static/js/home/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ require(
};

view.view_button_clicked = function (index) {
var app_info = model.data[index];
var app_info = model.app_data[index];

window.location = utils.url_path_join(
base_url,
Expand All @@ -29,13 +29,13 @@ require(
};

view.stop_button_clicked = function (index) {
var app_info = model.data[index];
var app_info = model.app_data[index];

var url_id = app_info.container.url_id;
return appapi.stop_application(url_id, {
success: function () {
view.reset_buttons_to_start(index);
app_info.container = null;
view.update_entry(index);
},
error: function (jqXHR, status, error) {
report_error(jqXHR, status, error);
Expand All @@ -44,8 +44,20 @@ require(

view.start_button_clicked = function (index) {
// The container is not running. This is a start button.
var mapping_id = model.data[index].mapping_id;
return appapi.start_application(mapping_id, {
var mapping_id = model.app_data[index].mapping_id;
var configurables_data = {};
var configurables = model.configurables[index];
configurables_data = {};

Object.getOwnPropertyNames(configurables).forEach(
function(val, idx, array) {
var configurable = configurables[val];
var tag = configurable.tag;
configurables_data[tag] = configurable.as_config_dict();
}
);

return appapi.start_application(mapping_id, configurables_data, {
error: function(jqXHR, status, error) {
report_error(jqXHR, status, error);
},
Expand Down
36 changes: 32 additions & 4 deletions remoteappmanager/static/js/home/models.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
define(['jquery'], function ($) {
define(['jquery', 'home/configurables'], function ($, configurables) {
"use strict";

var ApplicationListModel = function(remote_app_api) {
// (constructor) Model for the application list.
// Parameters
Expand All @@ -9,7 +9,13 @@ define(['jquery'], function ($) {
this._appapi = remote_app_api;

// Contains the data retrieved from the remote API
this.data = [];
this.app_data = [];

// Contains the submodels for the configurables.
// The values are aligned to the app_data index, and contain
// a dictionary that maps a supported (by the image) configurable tag
// to its client-side model.
this.configurables = [];
};

ApplicationListModel.prototype.update = function() {
Expand All @@ -19,10 +25,32 @@ define(['jquery'], function ($) {
// data. Note that, in error conditions, this routine resolves
// successfully in any case, and the data is set to empty list
var self = this;

return $.when(
self._appapi.available_applications_info()
).done(function (app_data) {
self.data = app_data;
self.app_data = app_data;
self.configurables = [];

// Add the options for some image types
for (var data_idx = 0; data_idx < self.app_data.length; ++data_idx) {
var image = self.app_data[data_idx].image;
self.configurables[data_idx] = {};

for (var cfg_idx = 0; cfg_idx < image.configurables.length; ++cfg_idx) {
var tag = image.configurables[cfg_idx];

// If this returns null, the tag has not been recognized
// by the client. skip it and let the server deal with the
// missing data, either by using a default or throwing
// an error.
var ConfigurableCls = configurables.from_tag(tag);

if (ConfigurableCls !== null) {
self.configurables[data_idx][tag] = new ConfigurableCls();
}
}
}
});
};

Expand Down
Loading