Nuria has uploaded a new change for review.
https://gerrit.wikimedia.org/r/157777
Change subject: [WIP] Adding removing options from browsing component
......................................................................
[WIP] Adding removing options from browsing component
Adding/removing options from side bar. Only interactions.
No style yet.
Change-Id: I34096c205f2d464efd68d6d962c16ab27dde6af9
---
M src/app/apis/wikimetrics.js
M src/components/project-selector/project-selector.html
M src/components/project-selector/project-selector.js
M src/components/wikimetrics-layout/wikimetrics-layout.html
M src/components/wikimetrics-layout/wikimetrics-layout.js
M src/css/layouts.css
M src/lib/logger.js
M stubs/fake-wikimetrics/projectLanguageChoices.json
8 files changed, 310 insertions(+), 36 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/analytics/dashiki
refs/changes/77/157777/1
diff --git a/src/app/apis/wikimetrics.js b/src/app/apis/wikimetrics.js
index dae97af..f32fdc1 100644
--- a/src/app/apis/wikimetrics.js
+++ b/src/app/apis/wikimetrics.js
@@ -9,8 +9,13 @@
this.root = config.wikimetricsDomain;
this.projectOptions = [];
this.languageOptions = [];
+ /** project selection present upon bootstrap **/
+ this.defaultProjects = [];
this.urlProjectLanguageChoices = config.urlProjectLanguageChoices;
this.categorizedMetricsUrl = config.categorizedMetricsUrl;
+
+ /** Given a project returns language and project friendly names*/
+ this.reverseLookup = {};
}
@@ -80,6 +85,13 @@
this.languageOptions = map.call(json[0], function (data) {
return new LanguageOption(data);
});
+
+ this.defaultProjects = map.call(json[2], function (data) {
+ return new ProjectOption(data);
+ });
+ //super hardcoded and fake
+ this.reverseLookup = json[3];
+
callback();
}.bind(this));
@@ -106,7 +118,7 @@
*
* {category: 'some category', name: 'some metric'}
**/
- WikimetricsApi.prototype.getCategorizedMetrics = function(callback) {
+ WikimetricsApi.prototype.getCategorizedMetrics = function (callback) {
return $.get(this.categorizedMetricsUrl).done(callback);
};
diff --git a/src/components/project-selector/project-selector.html
b/src/components/project-selector/project-selector.html
index a9d86f3..68fdb1b 100644
--- a/src/components/project-selector/project-selector.html
+++ b/src/components/project-selector/project-selector.html
@@ -4,16 +4,32 @@
projectOptions: projectOptions,
languageOptions: languageOptions,
select: displaySecondLevel
- }" class="typeahead search_box" autocomplete="off" size="20"/>
+ } , event
{blur:function(data,event){setTimeout(hideSecondLevel.bind($data),500)}}"
class="typeahead search_box" autocomplete="off" size="20"/>
-<span class="tt-dropdown-menu" data-bind="css: {open: displaySuboptions},
click: hideSecondLevel">
+<span class="tt-dropdown-menu" data-bind="css: {open: displaySuboptions},
+event:{blur:function(data,event){setTimeout(hideSecondLevel.bind($data),200);}}">
<div class="tt-dataset-suboptions">
<span class="header" data-bind="text: selectedOption"></span>
<hr/>
<span class="tt-suggestions">
<!-- ko foreach: suboptions -->
- <div class="tt-suggestion" data-bind="text: option"></div>
+ <div class="tt-suggestion" data-bind="text: name,
+ click: function(data,event){$parent.addProject(data);}"></div>
+ <span class="hidden" data-bind="text:project"> </span>
<!-- /ko -->
</span>
</div>
</span>
+
+<hr/>
+
+<div class="ui" style=" width:300px">
+<!-- ko foreach: selectionForDisplay -->
+ <span class="ui large label" data-bind="text:name"> </span>
+ <i class="delete icon" data-bind="click:
function(data,event){$parent.removeCategory(data);}"></i>
+ <!-- ko foreach: languages -->
+ <div data-bind="text:name"> </div>
+ <i class="delete icon" data-bind="click:
function(data,event){$parents[1].removeCategory(data);}"></i>
+ <!-- /ko -->
+<!-- /ko -->
+</div>
diff --git a/src/components/project-selector/project-selector.js
b/src/components/project-selector/project-selector.js
index 6d7d113..d5b46e8 100644
--- a/src/components/project-selector/project-selector.js
+++ b/src/components/project-selector/project-selector.js
@@ -1,22 +1,146 @@
/* jshint -W098 */
define(['knockout', 'text!./project-selector.html', './bindings'], function
(ko, templateMarkup) {
'use strict';
+ /**
+ * A selection item is of this form
+ {
+ 'name': projectData.name,
+ 'languages': [{
+ 'name': language,
+ 'project': data.project
+ }]
+ }
+ **/
+ function SelectionItem(projectName, project, languageName) {
+ this.name = projectName;
+ this.languages = [];
+ if (project && projectName) {
+ this.addLanguage(project, languageName);
+ }
+
+
+ }
+
+ function LanguageItem(project, languageName) {
+ this.name = languageName;
+ this.project = project;
+ }
+
+ /** Adds a language to the project selection if it is not already there **/
+ SelectionItem.prototype.addLanguage = function (project, languageName) {
+ var found = false;
+ for (var i = 0; i < this.languages.length; i++) {
+ if (this.languages[i].project.trim() === project.trim()) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ this.languages.push(new LanguageItem(project, languageName));
+ }
+ };
+
+ SelectionItem.prototype.addLanguages = function (languages) {
+ this.languages = languages;
+ };
+
function ProjectSelector(params) {
-
+ var self = this;
this.projectOptions = params.projectOptions();
this.languageOptions = params.languageOptions();
- /** options selected upon bootstrap if any **/
- this.defaultProjects = params.defaultProjects;
this.displaySuboptions = ko.observable(false);
this.selectedOption = ko.observable();
this.suboptions = ko.observableArray([]);
+ this.reverseLookup = params.reverseLookup();
+ this.selectionForDisplay = ko.observableArray([]);
+ this.setSelectionForDisplay(params.defaultProjects);
+
+ /** From the selectionfrom display
+ calculates the projects the visualization component cares about:
+ input:
+ [{
+ "name": "Wikipedia",
+ "languages": [{
+
+ "name": "English",
+ "project": "enwiki"
+ }, {
+ "name": "German",
+ "project": "dewiki"
+ }]
+ }, {
+ "name": "WikiSomething",
+ "languages": [{
+ "name": "Spanish",
+ "project": "essomethingwiki"
+ }, {
+ "name": "German",
+ "project": "desomethingwiki"
+ }]
+ }],
+
+ output:
+ [enwiki, dewiki, essomethingwiki, desomethingwiki]
+ **/
+ this.addedProjects = ko.computed(function () {
+ var selectionForDisplay = this.selectionForDisplay();
+ var projects = [];
+
+ if (selectionForDisplay.length > 0) {
+ selectionForDisplay.map(function (item) {
+ var languages = item.languages;
+ for (var i = 0; i < languages.length; i++) {
+ projects.push(languages[i].project);
+ }
+ return projects;
+ });
+ }
+ return projects;
+ }, this);
}
+
+ /**
+ * Turns a plain json array of objs like:
+ [{
+ "name": "Wikipedia",
+ "languages": [{
+
+ "name": "English",
+ "project": "enwiki"
+ }, {
+ "name": "German",
+ "project": "dewiki"
+ }]
+ }, {
+ "name": "WikiSomething",
+ "languages": [{
+ "name": "Spanish",
+ "project": "essomethingwiki"
+ }, {
+ "name": "German",
+ "project": "desomethingwiki"
+ }]
+ }],
+ into richer SelectionItems objects we can use with more ease
+ **/
+ ProjectSelector.prototype.setSelectionForDisplay = function
(defaultOptionsRaw) {
+ var selectionForDisplay = [];
+ var defaultOptions = defaultOptionsRaw();
+ for (var i = 0; i < defaultOptions.length; i++) {
+ var selectionItem = new SelectionItem(defaultOptions[i].name);
+ selectionItem.addLanguages(defaultOptions[i].languages);
+ selectionForDisplay.push(selectionItem);
+ }
+ this.selectionForDisplay(selectionForDisplay);
+ this.selectionForDisplay.sort();
+ };
function makeOptions(obj) {
return Object.getOwnPropertyNames(obj).map(function (p) {
return {
- option: p
+ name: p,
+ project: obj[p]
};
});
}
@@ -36,6 +160,62 @@
this.suboptions([]);
};
+ ProjectSelector.prototype.addProject = function (data) {
+ // get project nice name and language nice name
+ var projectData = this.reverseLookup[data.project];
+ // add them to side bar list
+ // o(n) on number of projects added at worst, can of course be improved
+
+ // try to see if this is a new category project
+ var existingItems = this.selectionForDisplay.remove(function (item) {
+ var category = item.name;
+ return item.name === projectData.name;
+ });
+
+ var language = projectData.language;
+
+ if (existingItems.length > 0) {
+ // new language in existing category, add it to set
+ var existingItem = existingItems[0];
+ existingItem.addLanguage(data.project, projectData.language);
+
+ this.selectionForDisplay.push(existingItem);
+ this.selectionForDisplay.sort();
+
+ } else {
+
+ // new category
+ var item = new SelectionItem(projectData.name, data.project,
language);
+
+ this.selectionForDisplay.push(item);
+ this.selectionForDisplay.sort();
+ }
+
+ this.hideSecondLevel();
+ };
+
+ ProjectSelector.prototype.removeProject = function (data) {
+ //there is a bug invoking this function
+ // sometimes does not get called?
+ var existingItem = this.selectionForDisplay.remove(function (item) {
+ var languages = item.languages;
+ var found = false;
+ for (var i; i < languages.length; i++) {
+ if (languages.project === data.project.trim()) {
+ found = true;
+ }
+ }
+ return found;
+ });
+ };
+
+ ProjectSelector.prototype.removeCategory = function (data) {
+ // get project nice name and language nice name
+ var existingItem = this.selectionForDisplay.remove(function (item) {
+ return item.name.trim() === data.name.trim();
+ });
+ };
+
return {
viewModel: ProjectSelector,
template: templateMarkup
diff --git a/src/components/wikimetrics-layout/wikimetrics-layout.html
b/src/components/wikimetrics-layout/wikimetrics-layout.html
index 48fcb00..05927f7 100644
--- a/src/components/wikimetrics-layout/wikimetrics-layout.html
+++ b/src/components/wikimetrics-layout/wikimetrics-layout.html
@@ -2,7 +2,8 @@
<section class="col span_small projects-container">
<project-selector params="{ projectOptions:projectOptions,
languageOptions:languageOptions,
- defaultProjects: defaultProjects}">
+ defaultProjects: defaultProjects,
+ reverseLookup: reverseLookup}">
</project-selector>
</section>
diff --git a/src/components/wikimetrics-layout/wikimetrics-layout.js
b/src/components/wikimetrics-layout/wikimetrics-layout.js
index cce9223..da6521b 100644
--- a/src/components/wikimetrics-layout/wikimetrics-layout.js
+++ b/src/components/wikimetrics-layout/wikimetrics-layout.js
@@ -13,19 +13,23 @@
self.selectedProjects = ko.observableArray([]);
self.projectOptions = ko.observableArray([]);
self.languageOptions = ko.observableArray([]);
- self.defaultProjects = [];
+ self.defaultProjects = ko.observableArray([]);
+ self.reverseLookup = ko.observable();
wikimetricsApi.getProjectAndLanguageChoices(function () {
self.languageOptions(wikimetricsApi.languageOptions);
self.projectOptions(wikimetricsApi.projectOptions);
+ self.defaultProjects(wikimetricsApi.defaultProjects);
+ self.reverseLookup(wikimetricsApi.reverseLookup);
});
- self.selectedProjects = ko.observableArray();
+ /** infer selected projects from defaultProjectSelection object which
is taylored for the ui **/
+
self.metricData = ko.observable();
wikimetricsApi.getCategorizedMetrics(self.metricData);
- self.metrics = ko.computed(function() {
+ self.metrics = ko.computed(function () {
var configData = this.metricData();
if (configData) {
return configData.categorizedMetrics;
@@ -33,7 +37,7 @@
return [];
}, self);
- self.defaultMetrics = ko.computed(function() {
+ self.defaultMetrics = ko.computed(function () {
var configData = this.metricData();
if (configData) {
return configData.defaultMetrics;
diff --git a/src/css/layouts.css b/src/css/layouts.css
index 9e54ee2..9901abb 100644
--- a/src/css/layouts.css
+++ b/src/css/layouts.css
@@ -15,3 +15,7 @@
.span_small { position: relative; width: 100%; right: 0; }
.span_large { position: relative; width: 100%; left: 0; }
}
+
+.hidden {
+ display:none;
+}
diff --git a/src/lib/logger.js b/src/lib/logger.js
index d383313..3c253bd 100644
--- a/src/lib/logger.js
+++ b/src/lib/logger.js
@@ -1,4 +1,4 @@
-define([], function() {
+define([], function () {
'use strict';
/**
* Logger for client side errors.
@@ -22,16 +22,17 @@
window.logger = {
- error: function(message) {
+ error: function (message) {
console.log(this._getTimestamp() + message);
},
- _getTimestamp: function() {
+ _getTimestamp: function () {
return new Date().toUTCString();
}
};
// registering for window.onerror, although many events do not trigger this
- window.onerror = function(message, file, line) {
+ window.onerror = function (message, file, line) {
logger.error(file + ':' + line + '\n\n' + message);
};
+
});
diff --git a/stubs/fake-wikimetrics/projectLanguageChoices.json
b/stubs/fake-wikimetrics/projectLanguageChoices.json
index 1b7803e..d10a864 100644
--- a/stubs/fake-wikimetrics/projectLanguageChoices.json
+++ b/stubs/fake-wikimetrics/projectLanguageChoices.json
@@ -3,41 +3,41 @@
"name": "English",
"description": "All projects",
"projects": {
- "Wikipedia": "eswiki",
- "Somethingwiki": "somewiki",
- "Wikidictionary": "somewiki"
+ "Wikipedia": "enwiki",
+ "WikiSomething": "ensomethingwiki",
+ "Wikidictionary": "endictionarywiki"
}
}, {
"name": "German",
"description": "All projects",
"projects": {
"Wikipedia": "dewiki",
- "SomethingGermanWiki": "somewiki",
- "Wikidictionary": "somewiki"
+ "WikiSomething": "desomethingwiki",
+ "Wikidictionary": "dedictionarywiki"
}
}, {
"name": "Spanish",
"description": "All projects",
"projects": {
"Wikipedia": "eswiki",
- "SomethingSpanishWiki": "somewiki",
- "Wikidictionary": "somewiki"
+ "WikiSomething": "essomethingwiki",
+ "Wikidictionary": "esdictionarywiki"
}
}, {
"name": "Cantonese",
"description": "All projects",
"projects": {
"Wikipedia": "cawiki",
- "SomethingCantoneseWiki": "somewiki",
- "Wikidictionary": "somewiki"
+ "WikiSomething": "casomethingwiki",
+ "Wikidictionary": "cadictionarywiki"
}
}, {
"name": "Catalan",
"description": "All projects",
"projects": {
- "Wikipedia": "cawiki",
- "SomethingCatalanWiki": "somewiki",
- "Wikidictionary": "somewiki"
+ "Wikipedia": "catwiki",
+ "WikiSomething": "catsomethingwiki",
+ "Wikidictionary": "catdictionarywiki"
}
}],
[{
@@ -52,17 +52,17 @@
"name": "WikiSomething",
"description": "100 languages",
"languages": {
- "Spanish": "eswiki",
- "English": "enwiki",
- "German": "dewiki"
+ "Spanish": "essomethingwiki",
+ "English": "ensomethingwiki",
+ "German": "desomethingwiki"
}
}, {
"name": "Wikitionary",
"description": "170 languages",
"languages": {
- "Spanish": "eswiki",
- "English": "enwiki",
- "German": "dewiki"
+ "Spanish": "esdictionarywiki",
+ "English": "endictionarywiki",
+ "German": "dedictionarywiki"
}
}, {
"name": "Commons",
@@ -70,5 +70,61 @@
"languages": {
"Mandarin": "mawiki"
}
- }]
+ }],
+ [{
+ "name": "Wikipedia",
+ "languages": [{
+
+ "name": "English",
+ "project": "enwiki"
+ }, {
+ "name": "German",
+ "project": "dewiki"
+ }]
+ }, {
+ "name": "WikiSomething",
+ "languages": [{
+ "name": "Spanish",
+ "project": "essomethingwiki"
+ }, {
+ "name": "German",
+ "project": "desomethingwiki"
+ }]
+ }],
+
+ {
+ "enwiki": {
+ "name": "Wikipedia",
+ "language": "English"
+ },
+ "dewiki": {
+ "name": "Wikipedia",
+ "language": "German"
+ },
+ "eswiki": {
+ "name": "Wikipedia",
+ "language": "Spanish"
+ },
+ "catwiki": {
+ "name": "Wikipedia",
+ "language": "Catalan"
+ },
+ "ensomethingwiki": {
+ "name": "Wikisomething",
+ "language": "English"
+ },
+ "desomethingwiki": {
+ "name": "WikiSomething",
+ "language": "German"
+ },
+ "essomethingwiki": {
+ "name": "WikiSomething",
+ "language": "Spanish"
+ },
+ "catsomethingwiki": {
+ "name": "WikiSomething",
+ "language": "Catalan"
+ }
+ }
+
]
--
To view, visit https://gerrit.wikimedia.org/r/157777
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I34096c205f2d464efd68d6d962c16ab27dde6af9
Gerrit-PatchSet: 1
Gerrit-Project: analytics/dashiki
Gerrit-Branch: master
Gerrit-Owner: Nuria <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits