From ec349d9bb4a94dce688edc283c44c9d65432a8a6 Mon Sep 17 00:00:00 2001 From: blue Date: Wed, 28 Nov 2018 09:54:14 +0300 Subject: [PATCH] an ability to create panes actions, player frontend draft --- libjs/wController/imagePane.js | 90 ++++++++++++++++++++++++-- libjs/wController/localModel.js | 10 +++ libjs/wController/panesList.js | 40 +++++++++++- lorgar/core/lorgar.js | 3 + lorgar/main.js | 1 + lorgar/views/button.js | 5 ++ lorgar/views/pane.js | 16 ++++- lorgar/views/panesList.js | 6 +- lorgar/views/player.js | 6 ++ magnus/lib/wModel/proxy/CMakeLists.txt | 1 + magnus/lib/wModel/proxy/pane.js | 39 ++++++++++- magnus/lib/wModel/proxy/panesList.js | 66 +++++++++++++++++++ magnus/pages/album.js | 11 ++-- magnus/pages/artist.js | 13 ++-- magnus/pages/list.js | 15 +++-- magnus/pages/music.js | 10 ++- 16 files changed, 304 insertions(+), 28 deletions(-) create mode 100644 magnus/lib/wModel/proxy/panesList.js diff --git a/libjs/wController/imagePane.js b/libjs/wController/imagePane.js index 077e2c1..a421784 100644 --- a/libjs/wController/imagePane.js +++ b/libjs/wController/imagePane.js @@ -4,26 +4,97 @@ var Address = require("../wType/address"); var Vocabulary = require("./vocabulary"); var File = require("./file/file"); +var LM = require("./localModel"); var ImagePane = Vocabulary.inherit({ "className": "ImagePane", "constructor": function(addr) { Vocabulary.fn.constructor.call(this, addr); + this._actions = []; + this._hasPageLink = false; this._hasImage = false; this.image = null; }, - "addElement": function(key, element) { - if (key === "image" && !this._hasImage) { - this._hasImage = true; - this.image = new File(new Address(["images", element.toString()])); - this.addForeignController("Corax", this.image); + "_actionActivate": function(name) { + var actObj = standardActions[name]; + + actObj.handler(this); + }, + "addAction": function(action) { + var type = action.at("type").valueOf(); + var obj = Object.create(null); + var supported = true; + + obj.type = type; + + switch (type) { + case 0: + var act = action.at("action").toString(); + var actObj = standardActions[act]; + if (actObj === undefined) { + this.trigger("seviceMessage", "Action " + act + " is not supported in ImagePanel, skipping"); + supported = false; + } + var model = new LM(""); + model.enabled = true; + model.hasLabel = true; + model.label = new LM(actObj.name); + model.addController(model.label); + model.activate = this._actionActivate.bind(this, act); + + obj.model = model; + obj.action = act; + break; } + + if (supported) { + this._actions.push(obj); + this.trigger("addAction", obj.model); + } + }, + "addElement": function(key, element) { + switch (key) { + case "image": + if (!this._hasImage) { + this._hasImage = true; + this.image = new File(new Address(["images", element.toString()])); + this.addForeignController("Corax", this.image); + } + break; + case "hasPageLink": + this._hasPageLink = element.valueOf(); + break; + case "actions": + var size = element.length(); + for (var i = 0; i < size; ++i) { + this.addAction(element.at(i)); + } + } + Vocabulary.fn.addElement.call(this, key, element); }, + "getActions": function() { + var models = []; + for (var i = 0; i < this._actions.length; ++i) { + models.push(this._actions[i].model); + } + + return models; + }, + "getPageLink": function() { + if (this._hasPageLink) { + return this.data.at("pageLink").clone(); + } else { + throw new Error("An attempt to request a page link from pane which doesn't have it"); + } + }, "hasImage": function() { return this._hasImage; }, + "hasPageLink": function() { + return this._hasPageLink; + }, "removeElement": function(key) { Vocabulary.fn.removeElement.call(this, key); @@ -37,4 +108,13 @@ var ImagePane = Vocabulary.inherit({ } }); +var standardActions = { + "play": { + handler: function (obj) { + window.play(obj); + }, + name: "Play" + } +}; + module.exports = ImagePane; diff --git a/libjs/wController/localModel.js b/libjs/wController/localModel.js index 46b1901..3343a6f 100644 --- a/libjs/wController/localModel.js +++ b/libjs/wController/localModel.js @@ -24,6 +24,16 @@ var LocalModel = Subscribable.inherit({ this.initialized = true; } }, + "destructor": function() { + for (var i = 0; i < this._controllers.length; ++i) { + this._controllers[i].destructor(); + } + + Subscribable.fn.destructor.call(this); + }, + "addController": function(ctrl) { + this._controllers.push(ctrl); + }, "setData": function(data) { this.data = data; this.initialized = true; diff --git a/libjs/wController/panesList.js b/libjs/wController/panesList.js index 00a8213..1454e4a 100644 --- a/libjs/wController/panesList.js +++ b/libjs/wController/panesList.js @@ -9,15 +9,28 @@ var PanesList = List.inherit({ "constructor": function PanesListModel(addr) { List.fn.constructor.call(this, addr); + this.actions = null; + this._subscriptionStart = 0; this._subscriptionEnd = Infinity; }, + "destructor": function() { + if (this.initialized) { + this.actions.destructor(); + } + + List.fn.destructor.call(this); + }, "addElement": function(element) { var size = this.data.length(); List.fn.addElement.call(this, element); if (size >= this._subscriptionStart && size < this._subscriptionEnd) { var controller = new ImagePane(this._pairAddress["+"](new Address([element.toString()]))); + var size = this.actions.length(); + for (var i = 0; i < size; ++i) { + controller.addAction(this.actions.at(i)); + } this.addController(controller); } }, @@ -25,6 +38,24 @@ var PanesList = List.inherit({ List.fn.clear.call(this); this.clearChildren(); }, + "_h_get": function(ev) { + this.clear(); + + var root = ev.getData(); + var data = root.at("data"); + + if (this.initialized) { + this.actions.destructor(); + } + this.actions = root.at("actions").clone(); + + var size = data.length(); + for (var i = 0; i < size; ++i) { + this.addElement(data.at(i).clone()); + } + this.initialized = true; + this.trigger("data"); + }, "setSubscriptionRange": function(s, e) { var needStart = s !== this._subscriptionStart; var needEnd = e !== this._subscriptionEnd; @@ -33,7 +64,8 @@ var PanesList = List.inherit({ var oe = this._subscriptionEnd; this._subscriptionStart = s; this._subscriptionEnd = e; - if (this._subscribed) { + if (this._subscribed && this.initialized) { + var size = this.actions.length(); this.trigger("rangeStart"); if (needStart) { if (s > os) { @@ -47,6 +79,9 @@ var PanesList = List.inherit({ var limit = Math.min(os, e) - s; for (var i = 0; i < limit; ++i) { var ctrl = new ImagePane(this._pairAddress["+"](new Address([this.data.at(i + s).toString()]))); + for (var a = 0; a < size; ++a) { + ctrl.addAction(this.actions.at(a)); + } this.addController(ctrl, i); } } @@ -59,6 +94,9 @@ var PanesList = List.inherit({ var amount = ce - start; //it can be negative, it's fine for (var i = 0; i < amount; ++i) { var ctrl = new ImagePane(this._pairAddress["+"](new Address([this.data.at(start + i).toString()]))); + for (var a = 0; a < size; ++a) { + ctrl.addAction(this.actions.at(a)); + } this.addController(ctrl); } } else if (ce < coe) { diff --git a/lorgar/core/lorgar.js b/lorgar/core/lorgar.js index bb7099c..801d0ca 100644 --- a/lorgar/core/lorgar.js +++ b/lorgar/core/lorgar.js @@ -231,6 +231,9 @@ "_onWindowResize": function() { this._body.setSize(document.body.offsetWidth, document.body.offsetHeight); }, + "play": function(id) { + console.log("Need to play " + id.toString()); + }, "_prepareNode": function(name, address, port) { if (this._nodes[name]) { throw new Error("An attempt to prepeare node " + name + " for the second time"); diff --git a/lorgar/main.js b/lorgar/main.js index a328497..31e06cb 100644 --- a/lorgar/main.js +++ b/lorgar/main.js @@ -32,6 +32,7 @@ window.unregisterForeignController = window.lorgar.unregisterForeignController.bind(window.lorgar); window.subscribeForeignController = window.lorgar.subscribeForeignController.bind(window.lorgar); window.unsubscribeForeignController = window.lorgar.unsubscribeForeignController.bind(window.lorgar); + window.play = window.lorgar.play.bind(window.lorgar); } } } diff --git a/lorgar/views/button.js b/lorgar/views/button.js index 7dbeaf5..6e00151 100644 --- a/lorgar/views/button.js +++ b/lorgar/views/button.js @@ -26,6 +26,11 @@ controller.on("setEnabled", this._onSetEnabled, this); controller.on("setLabel", this._onSetLabel, this); + + if (controller.initialized) { + this._onSetEnabled(controller.enabled); + this._onSetLabel(controller.hasLabel, controller.label); + } }, "destructor": function() { this._f.off("setEnabled", this._onSetEnabled, this); diff --git a/lorgar/views/pane.js b/lorgar/views/pane.js index 2e33e7c..ce4dd50 100644 --- a/lorgar/views/pane.js +++ b/lorgar/views/pane.js @@ -8,6 +8,7 @@ defineArray.push("views/layout"); defineArray.push("views/label"); defineArray.push("views/image"); + defineArray.push("views/button"); defineArray.push("lib/wController/localModel"); define(moduleName, defineArray, function() { @@ -15,6 +16,7 @@ var Layout = require("views/layout"); var Label = require("views/label"); var Image = require("views/image"); + var Button = require("views/button"); var LM = require("lib/wController/localModel"); var Pane = Layout.inherit({ @@ -46,6 +48,12 @@ this._f.on("newElement", this._onNewElement, this); this._f.on("removeElement", this._onRemoveElement, this); + this._f.on("addAction", this._onAddAction, this); + + var acts = this._f.getActions(); + for (var i = 0; i < acts.length; ++i) { + this._onAddAction(acts[i]); + } this._uncyclic.push(function() { lm.destructor(); @@ -56,6 +64,10 @@ Layout.fn.destructor.call(this); }, + "_onAddAction": function(model) { + var view = new Button(model); + this.append(view, Layout.Aligment.LeftTop) + }, "_applyProperties": function() { this._onAddProperty("secondaryColor", "background"); @@ -67,8 +79,8 @@ }; }, "_onClick": function() { - if (this._f.data.at("hasPageLink").valueOf() === true) { - this.trigger("activate", this._f.data.at("pageLink").clone()); + if (this._f.hasPageLink()) { + this.trigger("activate", this._f.getPageLink()); } }, "_onLabelChangeLimits": function(label) { diff --git a/lorgar/views/panesList.js b/lorgar/views/panesList.js index 08dac91..af62199 100644 --- a/lorgar/views/panesList.js +++ b/lorgar/views/panesList.js @@ -50,15 +50,13 @@ this._f.setSubscriptionRange(0, 0); }, "append": function(child, index) { - var model = new LM(); - var nest = new Layout(model, { + var nest = new Layout(helper, { minHeight: this._o.nestHeight, maxHeight: this._o.nestHeight, minWidth: this._o.nestWidth, minWidth: this._o.nestWidth, scrollable: Layout.Scroll.None }); - nest._uncyclic.push(function() {model.destructor()}); nest.append(child); child.on("activate", this._onChildActivate, this); //todo need to remove handler on deletion this._addChild(nest, 0, index); @@ -184,6 +182,8 @@ } }); + var helper = new LM(); + return PanesList; }); })(); diff --git a/lorgar/views/player.js b/lorgar/views/player.js index df01552..2c7cbef 100644 --- a/lorgar/views/player.js +++ b/lorgar/views/player.js @@ -6,6 +6,7 @@ deps.push("views/gridLayout"); deps.push("views/button"); deps.push("views/label"); + deps.push("views/view"); deps.push("lib/wController/localModel"); @@ -15,6 +16,7 @@ var GridLayout = require("views/gridLayout"); var Button = require("views/button"); var Label = require("views/label"); + var View = require("views/view"); var Model = require("lib/wController/localModel"); @@ -38,10 +40,12 @@ var artist = new Label(this._infoModels.artist); var album = new Label(this._infoModels.album); var song = new Label(this._infoModels.song); + var spacer = new View(helper); this.append(artist, 0, 2, 1, 1) this.append(song, 1, 2, 1, 1) this.append(album, 2, 2, 1, 1) + this.append(spacer, 0, 3, 3, 1); this._uncyclic.push(this._infoModels.artist.destructor.bind(this._infoModels.artist)); this._uncyclic.push(this._infoModels.song.destructor.bind(this._infoModels.song)); @@ -94,6 +98,8 @@ } }); + var helper = new Model(); + return Player; }); })() diff --git a/magnus/lib/wModel/proxy/CMakeLists.txt b/magnus/lib/wModel/proxy/CMakeLists.txt index 2ef4f4b..14b2608 100644 --- a/magnus/lib/wModel/proxy/CMakeLists.txt +++ b/magnus/lib/wModel/proxy/CMakeLists.txt @@ -6,3 +6,4 @@ add_jslib(wModel/proxy/vocabulary.js lib/wModel/proxy/vocabulary ${MAGNUS_DIR} n add_jslib(wModel/proxy/catalogue.js lib/wModel/proxy/catalogue ${MAGNUS_DIR} node) configure_file(pane.js pane.js) +configure_file(panesList.js panesList.js) diff --git a/magnus/lib/wModel/proxy/pane.js b/magnus/lib/wModel/proxy/pane.js index 5bc8b91..f3c4e4a 100644 --- a/magnus/lib/wModel/proxy/pane.js +++ b/magnus/lib/wModel/proxy/pane.js @@ -4,12 +4,18 @@ var MVocabulary = require("./vocabulary"); var Address = require("../../wType/address"); var Boolean = require("../../wType/boolean"); +var Uint64 = require("../../wType/uint64"); +var String = require("../../wType/string"); +var Vocabulary = require("../../wType/vocabulary"); +var Vector = require("../../wType/vector"); var Pane = MVocabulary.inherit({ "className": "Pane", - "constructor": function(address, controllerAddress, socket) { + "constructor": function(address, controllerAddress, socket, actions) { MVocabulary.fn.constructor.call(this, address, controllerAddress, socket); + this._actions = new Vector(); + this._createActions(actions || []); if (this.constructor.pageAddress) { this.hasPageLink = true; @@ -17,14 +23,45 @@ var Pane = MVocabulary.inherit({ this._pageLink = this.constructor.pageAddress["+"](new Address([id.toString()])); } }, + "destructor": function() { + this._actions.destructor(); + if (this.hasPageLink) { + this._pageLink.destructor(); + } + + MVocabulary.fn.destructor.call(this); + }, + "_createActions": function(actions) { + for (var i = 0; i < actions.length; ++i) { + var action = actions[i]; + var actionVC = new Vocabulary(); + actionVC.insert("type", new Uint64(action.type)); + var supported = false; + + switch (action.type) { + case 0: //this type of actions has only action itself, no additional arguments, what to do is desctibed in the view + actionVC.insert("action", new String(action.action)); + supported = true; + break; + } + + if (supported) { + this._actions.push(actionVC); + } else { + actionVC.destructor(); + } + } + }, "_getAllData": function() { var vc = this.controller.data.clone(); vc.insert("hasPageLink", new Boolean(this.hasPageLink)); + vc.insert("actions", this._actions.clone()); if (this.hasPageLink) { vc.insert("pageLink", this._pageLink.clone()); } + return vc; } }); diff --git a/magnus/lib/wModel/proxy/panesList.js b/magnus/lib/wModel/proxy/panesList.js new file mode 100644 index 0000000..cda0f8a --- /dev/null +++ b/magnus/lib/wModel/proxy/panesList.js @@ -0,0 +1,66 @@ +"use strict"; + +var Vocabulary = require("../../wType/vocabulary"); +var Uint64 = require("../../wType/uint64"); +var String = require("../../wType/string"); +var Vector = require("../../wType/vector"); + +var Catalogue = require("./catalogue"); + +var PanesList = Catalogue.inherit({ + "className": "PanesList", + "constructor": function(address, ctrlAddr, ctrlOpts, socket, actions) { + Catalogue.fn.constructor.call(this, address, ctrlAddr, ctrlOpts, socket); + + this._actions = new Vector(); + this._createActions(actions || []); + }, + "destructor": function() { + this._actions.destructor(); + + Catalogue.fn.destructor.call(this); + }, + "_createActions": function(actions) { + for (var i = 0; i < actions.length; ++i) { + var action = actions[i]; + var actionVC = new Vocabulary(); + actionVC.insert("type", new Uint64(action.type)); + var supported = false; + + switch (action.type) { + case 0: //this type of actions has only action itself, no additional arguments, what to do is desctibed in the view + actionVC.insert("action", new String(action.action)); + supported = true; + break; + } + + if (supported) { + this._actions.push(actionVC); + } else { + actionVC.destructor(); + } + } + }, + "_h_get": function(ev) { + if (this.ready) { + var vc = new Vocabulary(); + + vc.insert("data", this._getAllData()); + vc.insert("actions", this._actions.clone()); + this.response(vc, "get", ev); + } else { + this._waitingEvents.push(ev.clone()); + } + }, + "_onRemoteData": function() { + this.setReady(true); + + var vc = new Vocabulary(); + vc.insert("data", this._getAllData()); + vc.insert("actions", this._actions.clone()); + + this.broadcast(vc, "get") + } +}); + +module.exports = PanesList; diff --git a/magnus/pages/album.js b/magnus/pages/album.js index 62146a5..cf36d4f 100644 --- a/magnus/pages/album.js +++ b/magnus/pages/album.js @@ -2,7 +2,7 @@ var TempPage = require("./tempPage"); var String = require("../lib/wModel/string"); -var ProxyCatModel = require("../lib/wModel/proxy/catalogue"); +var PanesList = require("../lib/wModel/proxy/panesList"); var PaneModel = require("../lib/wModel/proxy/pane"); var Image = require("../lib/wModel/image"); var Model = require("../lib/wModel/model"); @@ -41,16 +41,19 @@ var AlbumPage = TempPage.inherit({ var spacer = new Model(this._address["+"](new Address(["spacer"]))); this.addItem(spacer, 0, 2, 2, 1); - this._songs = new ProxyCatModel( + this._songs = new PanesList( this._address["+"](new Address(["songs"])), new Address(["songs"]), { sorting: {ascending: true, field: "name"}, filter: {album: id.clone()} }, - proxySocket + proxySocket, + [{ + type: 0, + action: "play" + }] ); - this._songs.className = "PanesList"; var PaneClass = PaneModel.Songs; this._songs.setChildrenClass(PaneClass); this.addItem(this._songs, 2, 0, 1, 3, TempPage.Aligment.CenterTop); diff --git a/magnus/pages/artist.js b/magnus/pages/artist.js index ef496c7..b87aab6 100644 --- a/magnus/pages/artist.js +++ b/magnus/pages/artist.js @@ -2,7 +2,7 @@ var TempPage = require("./tempPage"); var String = require("../lib/wModel/string"); -var ProxyCatModel = require("../lib/wModel/proxy/catalogue"); +var PanesList = require("../lib/wModel/proxy/panesList"); var PaneModel = require("../lib/wModel/proxy/pane"); var VCController = require("../lib/wController/vocabulary"); @@ -22,7 +22,7 @@ var ArtistPage = TempPage.inherit({ header.addProperty("fontFamily", "casualFont"); this.addItem(header, 0, 0, 1, 1, TempPage.Aligment.CenterTop); - this._albums = new ProxyCatModel( + this._albums = new PanesList( this._address["+"](new Address(["albums"])), new Address(["albums"]), { @@ -36,16 +36,19 @@ var ArtistPage = TempPage.inherit({ this._albums.setChildrenClass(PaneClass); this.addItem(this._albums, 1, 0, 1, 1, TempPage.Aligment.CenterTop); - this._songs = new ProxyCatModel( + this._songs = new PanesList( this._address["+"](new Address(["songs"])), new Address(["songs"]), { sorting: {ascending: true, field: "name"}, filter: {artist: id.clone()} }, - proxySocket + proxySocket, + [{ + type: 0, + action: "play" + }] ); - this._songs.className = "PanesList"; var PaneClass = PaneModel.Songs; this._songs.setChildrenClass(PaneClass); this.addItem(this._songs, 2, 0, 1, 1, TempPage.Aligment.CenterTop); diff --git a/magnus/pages/list.js b/magnus/pages/list.js index e4c91d9..1e494c5 100644 --- a/magnus/pages/list.js +++ b/magnus/pages/list.js @@ -2,42 +2,45 @@ var Page = require("../lib/wModel/page"); var String = require("../lib/wModel/string"); -var ProxyCatModel = require("../lib/wModel/proxy/catalogue"); +var PanesList = require("../lib/wModel/proxy/panesList"); var PaneModel = require("../lib/wModel/proxy/pane"); var Address = require("../lib/wType/address"); var Uint64 = require("../lib/wType/uint64"); +var Vocabulary = require("../lib/wType/vocabulary"); var Handler = require("../lib/wDispatcher/handler"); var List = Page.inherit({ "className": "ListPage", - "constructor": function(address, name, remoteAddress, socket, ChildClass) { + "constructor": function(address, name, remoteAddress, socket, ChildClass, listOptions, paneActions) { Page.fn.constructor.call(this, address, name); this._proxySocket = socket; this._ChildClass = ChildClass; + this._listOptions = listOptions || new Vocabulary() var header = new String(this._address["+"](new Address(["header"])), name); header.addProperty("fontFamily", "casualFont"); this.addItem(header, 0, 0, 1, 1, Page.Aligment.CenterTop); - this._list = new ProxyCatModel( + this._list = new PanesList( this._address["+"](new Address(["list"])), remoteAddress, { sorting: {ascending: true, field: "name"} }, - socket + socket, + paneActions ); - this._list.className = "PanesList"; var PaneClass = PaneModel[name]; if (!PaneClass) { PaneClass = PaneModel.inherit({}); PaneClass.pageAddress = address; + PaneModel[name] = PaneClass; } this._list.setChildrenClass(PaneClass); - this.addItem(this._list, 1, 0, 1, 1, Page.Aligment.CenterTop); + this.addItem(this._list, 1, 0, 1, 1, Page.Aligment.CenterTop, new Uint64(List.getModelTypeId(this._list)), listOptions); this._reporterHandler = new Handler(this._address["+"](new Address(["subscribeMember"])), this, this._h_subscribeMember); }, diff --git a/magnus/pages/music.js b/magnus/pages/music.js index 50296c4..ef49732 100644 --- a/magnus/pages/music.js +++ b/magnus/pages/music.js @@ -7,6 +7,7 @@ var PanesList = require("../lib/wModel/panesList"); var Address = require("../lib/wType/address"); var Vocabulary = require("../lib/wType/vocabulary"); var Boolean = require("../lib/wType/boolean"); +var Uint64 = require("../lib/wType/uint64"); var Link = require("../lib/wModel/link"); @@ -135,12 +136,19 @@ var MusicPage = Page.inherit({ this._albumsLink.label.addProperty("color", "primaryFontColor"); this._albumsLink.addProperty("backgroundColor", "primaryColor"); + var lOpts = new Vocabulary(); + lOpts.insert("nestWidth", new Uint64(300)); this._songs = new List( this._addresses.songs.local.clone(), "Songs", this._addresses.songs.remote.clone(), socket, - Song + Song, + lOpts, + [{ + type: 0, + action: "play" + }] ); this._songsLink = new Link(this._address["+"](new Address(["songsLink"])), "Songs", this._addresses.songs.local.clone()); this._songsLink.label.addProperty("fontSize", "largeFontSize");