dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #30808
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 15663: Merge reworked menu and update event-capture
Merge authors:
Mark Polak (markpo)
------------------------------------------------------------
revno: 15663 [merge]
committer: Mark Polak <markpo@xxxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2014-06-13 01:42:40 +0200
message:
Merge reworked menu and update event-capture
added:
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.manager.js
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.ui.js
modified:
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/about/modules.vm
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/css/menu.css
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.js
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.translate.js
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/main.vm
dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/event-capture.appcache
dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/i18n/en.json
dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/i18n/fr.json
dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/index.html
dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/scripts/app.js
--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk
Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/about/modules.vm'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/about/modules.vm 2014-04-01 20:39:26 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/about/modules.vm 2014-06-11 20:02:19 +0000
@@ -12,3 +12,5 @@
</div>
<div id="appsMenu"></div>
+
+<script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.menu.manager.js?_rev=$!{buildRevision}"></script>
=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/css/menu.css'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/css/menu.css 2014-05-29 08:50:53 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/css/menu.css 2014-06-12 23:32:40 +0000
@@ -1,3 +1,14 @@
+/**
+ * Bootstrap 3.0 box-sizing fix
+ */
+#menuLinkArea * {
+ box-sizing: content-box;
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ -o-box-sizing: content-box;
+ -m-box-sizing: content-box;
+}
+
#menuLinkArea
{
list-style-type: none;
@@ -11,22 +22,33 @@
float: right;
}
-#apps-search {
+#menuLinkArea .app-menu-dropdown li {
+ float: left;
+}
+
+input.apps-search {
border: 1px solid #ccc;
border-radius: 3px;
+ box-sizing: content-box;
outline: none;
+ padding: 4px 1px;
padding-right: 25px;
padding-left: 5px;
width: 328px;
}
+input.apps-search[type="text"] {
+ padding-right: 5px;
+ width: 348px;
+}
+
.apps-search-wrap {
padding-bottom: 10px;
position: relative;
width: 360px;
}
-#apps-search-clear {
+.app-menu-dropdown .apps-search-clear {
color: #404040;
cursor: pointer;
display: none;
@@ -60,6 +82,10 @@
color: #000;
}
+.menuDropDownBox li.selected a {
+ background-color: #f5f5f7;
+}
+
.app-menu:after
{
clear: both;
@@ -238,6 +264,7 @@
a.menu-link:hover
{
+ color: #fff;
text-decoration: none;
}
@@ -251,18 +278,29 @@
border-radius: 2px;
box-shadow: rgba(0, 0, 0, 0.24) 0px 2px 8px 0px;
color: #000;
- display: none;
font-size: 9pt;
max-height: 610px;
overflow-y: inherit;
padding: 10px;
+ top: 10px;
+ position: relative;
width: 360px;
z-index: 10;
}
+.app-menu-dropdown-wrap {
+ position: absolute;
+ left: -9999px;
+}
+
+.app-menu-hide {
+ display: none;
+}
+
.app-menu-dropdown ul
{
margin: 0;
+ overflow: auto;
}
.app-menu-dropdown li
@@ -317,6 +355,7 @@
display: block;
height: 110px;
padding: 0;
+ text-decoration: none;
width: 120px;
}
@@ -352,6 +391,14 @@
margin-left: 5px;
}
+.app-menu-dropdown:after {
+ content: " "; /* Older browser do not support empty content */
+ visibility: hidden;
+ display: block;
+ height: 0;
+ clear: both;
+}
+
.apps-menu-bottom-button a:hover
{
color: #fff;
@@ -404,20 +451,14 @@
width: 384px;
}
-#appsDropDown ul.menuDropDownBox {
+#appsMenuDropDown ul.menuDropDownBox {
height: 330px;
}
-#appsDropDown .caret-up-background,
-#appsDropDown .caret-up-border
-{
- left: 296px;
-}
-
-#profileDropDown .caret-up-background,
-#profileDropDown .caret-up-border
-{
- left: 292px;
+.caret-up-background,
+.caret-up-border
+{
+ left: 298px;
}
.drop-down-menu-link
=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.js 2014-05-24 08:58:21 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.js 2014-06-11 20:02:19 +0000
@@ -37,11 +37,47 @@
return Object.prototype.toString.call(obj) == '[object Function]';
}
},
+ getBaseUrl = (function () {
+ var href = window.location.origin;
+ return function () {
+ var urlParts = href.split("/"),
+ baseUrl;
+
+ if (dhis2.settings.baseUrl === undefined) {
+ return "..";
+ }
+
+ if (typeof dhis2.settings.baseUrl !== "string") {
+ throw new TypeError("Dhis2 settings: baseUrl should be a string");
+ }
+
+ if (urlParts[urlParts.length - 1] !== "") {
+ baseUrl = href + '/' + dhis2.settings.baseUrl;
+ } else {
+ urlParts.pop();
+ urlParts.push(dhis2.settings.baseUrl);
+ baseUrl = urlParts.join('/');
+ }
+ return baseUrl;
+ }
+ })(),
+ /**
+ * Adjusts the url to include the baseUrl
+ *
+ * @param iconUrl
+ * @returns {String}
+ */
+ fixUrlIfNeeded = function (iconUrl) {
+ if (iconUrl.substring(0, 2) === "..") {
+ return getBaseUrl() + iconUrl.substring(2, iconUrl.length);
+ }
+ return iconUrl;
+ },
/**
* Object that represents the list of menu items
* and managers the order of the items to be saved.
*/
- menuItemsList = (function () {
+ menuItemsList = function () {
var menuOrder = [],
menuItems = {};
@@ -69,14 +105,14 @@
return menuOrder;
}
}
- })();
+ };
dhis2.menu = {};
- dhis2.menu = function () {
+ dhis2.menu = function (nameKey, preLoadedData) {
var that = {},
menuReady = false,
- menuItems = menuItemsList,
+ menuItems = menuItemsList(),
callBacks = [], //Array of callbacks to call when serviced is updated
onceCallBacks = [];
@@ -85,7 +121,9 @@
**********************************************************************/
function processTranslations(translations) {
- var items = dhis2.menu.getApps();
+ var items = that.getApps();
+
+ that.name = translations[nameKey];
items.forEach(function (element, index, items) {
if (element.id && translations[element.id]) {
@@ -112,7 +150,7 @@
* Execute any callbacks that are set onto the callbacks array
*/
function executeCallBacks() {
- var onceCallBack, callBackIndex;
+ var onceCallBack;
//If not ready or no menu items
if ( ! isReady() || menuItems === {})
@@ -121,10 +159,10 @@
//Execute the single time callbacks
while (onceCallBacks.length !== 0) {
onceCallBack = onceCallBacks.pop();
- onceCallBack(menuItems);
+ onceCallBack.apply(that, [that]);
}
callBacks.forEach(function (callback, index, callBacks) {
- callback.apply(dhis2.menu, [menuItems]);
+ callback.apply(that, [that]);
});
}
@@ -170,6 +208,8 @@
* Public methods
**********************************************************************/
+ that.id = nameKey;
+ that.name = nameKey;
that.displayOrder = 'custom';
that.getMenuItems = function () {
@@ -234,12 +274,19 @@
that.addMenuItems = function (items) {
var keysToTranslate = [];
+ //Add the name of the menu to the translationList
+ keysToTranslate.push(nameKey);
+
items.forEach(function (item, index, items) {
item.id = item.name;
keysToTranslate.push(item.name);
if(item.description === "") {
keysToTranslate.push("intro_" + item.name);
}
+
+ item.defaultAction = fixUrlIfNeeded(item.defaultAction);
+ item.icon = fixUrlIfNeeded(item.icon);
+
menuItems.setItem(item.id, item);
});
@@ -257,11 +304,12 @@
var once = onlyOnce ? true : false;
if ( ! du.isFunction(callback)) {
+ setTimeout(executeCallBacks, 300);
return false;
}
- if (menuItems !== undefined) {
- callback(menuItems);
+ if (isReady() && (menuItems !== undefined)) {
+ callback(that);
}
if (true === once) {
@@ -305,7 +353,7 @@
* @returns {Array} Array of app objects
*/
that.getOrderedAppList = function () {
- var favApps = dhis2.menu.getFavorites(),
+ var favApps = that.getFavorites(),
nonFavApps = that.getNonFavoriteApps();
switch (that.displayOrder) {
case 'name-asc':
@@ -319,7 +367,7 @@
}
that.updateOrder = function (reorderedApps) {
- switch (dhis2.menu.displayOrder) {
+ switch (that.displayOrder) {
case 'name-asc':
case 'name-desc':
that.updateFavoritesFromList(reorderedApps);
@@ -340,199 +388,11 @@
return saveMethod(that.getMenuItems().getOrder());
}
- return that;
- }();
-})(dhis2 = dhis2 || {});
-
-/**
- * Created by Mark Polak on 28/01/14.
- *
- * @description jQuery part of the menu
- *
- * @see jQuery (http://jquery.com)
- * @see jQuery Template Plugin (http://github.com/jquery/jquery-tmpl)
- */
-
-/* Function used for checking dependencies for the menu
-(function (required_libs, undefined) {
- var libraries = [
- { name: "jQuery", variable: "jQuery", url: "http://jquery.com" },
- { name: "jQuery Template Plugin", variable: "jQuery.template", url: "http://github.com/jquery/jquery-tmpl" }
- ];
-
- //In IE 8 we can not use console
- if (typeof console === "undefined") {
- return;
- }
-
- //Throw error for the required libraries
- libraries.forEach(function (library, index, libraries) {
- if (window[library] === undefined) {
- console.error("Missing required library: " + library.name + ". Please see (" + library.url + ")");
- }
- });
-})();
-*/
-
-(function ($, menu, undefined) {
- var markup = '',
- selector = 'appsMenu';
-
- markup += '<li data-id="${id}" data-app-name="${name}" data-app-action="${defaultAction}">';
- markup += ' <a href="${defaultAction}" class="app-menu-item">';
- markup += ' <img src="${icon}" onError="javascript: this.onerror=null; this.src = \'../icons/program.png\';">';
- markup += ' <span>${name}</span>';
- markup += ' <div class="app-menu-item-description"><span class="bold">${name}</span><i class="fa fa-arrows"></i><p>${description}</p></div>';
- markup += ' </a>';
- markup += '</li>';
-
- $.template('appMenuItemTemplate', markup);
-
- function renderDropDownFavorites() {
- var selector = '#appsDropDown .menuDropDownBox',
- apps = dhis2.menu.getOrderedAppList();
-
- $('#appsDropDown').addClass('app-menu-dropdown ui-helper-clearfix');
- $(selector).html('');
- $.tmpl( "appMenuItemTemplate", apps).appendTo(selector);
- }
-
- function renderAppManager(selector) {
- var apps = dhis2.menu.getOrderedAppList();
- $('#' + selector).html('');
- $('#' + selector).append($('<ul></ul><hr class="app-separator">').addClass('ui-helper-clearfix'));
- $('#' + selector).addClass('app-menu');
- $.tmpl( "appMenuItemTemplate", apps).appendTo('#' + selector + ' ul');
-
- //Add favorites icon to all the menu items in the manager
- $('#' + selector + ' ul li').each(function (index, item) {
- $(item).children('a').append($('<i class="fa fa-bookmark"></i>'));
- });
-
- twoColumnRowFix();
- }
-
- /**
- * Saves the given order to the server using jquery ajax
- *
- * @param menuOrder {Array}
- */
- function saveOrder(menuOrder) {
- if (menuOrder.length !== 0) {
- //Persist the order on the server
- $.ajax({
- contentType:"application/json; charset=utf-8",
- data: JSON.stringify(menuOrder),
- dataType: "json",
- type:"POST",
- url: "../api/menu/"
- }).success(function () {
- //TODO: Give user feedback for successful save
- }).error(function () {
- //TODO: Give user feedback for failure to save
- });
- }
- }
-
- /**
- * Resets the app blocks margin in case of a resize or a sort update.
- * This function adds a margin to the 9th element when the screen is using two columns to have a clear separation
- * between the favorites and the other apps
- *
- * @param event
- * @param ui
- */
- function twoColumnRowFix(event, ui) {
- var self = $('.app-menu ul'),
- elements = $(self).find('li:not(.ui-sortable-helper)');
-
- elements.each(function (index, element) {
- $(element).css('margin-right', '0px');
- if ($(element).hasClass('app-menu-placeholder')) {
- $(element).css('margin-right', '10px');
- }
- //Only fix the 9th element when we have a small enough screen
- if (index === 8 && (self.width() < 808)) {
- $(element).css('margin-right', '255px');
- }
- });
-
- }
-
- /**
- * Render the menumanager and the dropdown menu and attach the update handler
- */
- //TODO: Rename this as the name is not very clear to what it does
- function renderMenu() {
- var options = {
- placeholder: 'app-menu-placeholder',
- connectWith: '.app-menu ul',
- update: function (event, ui) {
- var reorderedApps = $("#" + selector + " ul"). sortable('toArray', {attribute: "data-id"});
-
- dhis2.menu.updateOrder(reorderedApps);
- dhis2.menu.save(saveOrder);
-
- //Render the dropdown menu
- renderDropDownFavorites();
- },
- sort: twoColumnRowFix,
- tolerance: "pointer",
- cursorAt: { left: 55, top: 30 }
- };
-
- renderAppManager(selector);
- renderDropDownFavorites();
-
- $('.app-menu ul').sortable(options).disableSelection();
- }
-
- menu.subscribe(renderMenu);
-
- /**
- * jQuery events that communicate with the web api
- * TODO: Check the urls (they seem to be specific to the dev location atm)
- */
- $(function () {
- var menuTimeout = 500,
- closeTimer = null,
- dropDownId = null,
- dropDownHooks = (function () {
- var hook_library = {};
-
- return {
- get: function (id) {
- if (hook_library[id] && hook_library[id].length > 0) {
- return hook_library[id];
- } else {
- return [];
- }
- },
- addHook: function (id, hook) {
- hook_library[id] = hook_library[id] || [];
- hook_library[id].push(hook);
- }
- };
- })();
-
- function performSearch() {
- var menuItems = [],
- searchFor = $('#apps-search').val().toLowerCase(),
+ that.search = function (searchFor) {
+ //Get all the apps
+ var menuItems = that.getApps(),
searchMatches = [];
- //Re-render all the apps
- renderDropDownFavorites();
-
- if (searchFor === '') {
- $('#apps-search-clear').hide();
- $('#apps-search').focus();
- return;
- }
- $('#apps-search-clear').show();
-
- //Get all the apps
- menuItems = menu.getApps();
-
//Find the matches
menuItems.forEach(function (menuItem) {
var menuItemName = menuItem.name.toLowerCase(),
@@ -544,7 +404,7 @@
}
});
- //Order the search matches on occurance
+ //Order the search matches on occurrence
searchMatches.sort(function (a, b) {
if (a.searchScore < b.searchScore)
return -1;
@@ -553,221 +413,16 @@
return 0;
});
- //Remove all the apps
- $(dropDownId).find('ul').find('li').remove();
-
- //Add the apps that match the search back to the menu
- $.tmpl( "appMenuItemTemplate", searchMatches).appendTo(dropDownId + ' ul');
- }
-
- function goToFirstMenuItem() {
- var menuItemUrl = $(dropDownId).find('ul li').first().find('a').attr('href');
- if (menuItemUrl) {
- window.location = menuItemUrl;
- }
- }
-
- dropDownHooks.addHook('appsDropDown', function () {
- var dropDownId = this;
- $(dropDownId).find('#apps-search').focus();
-
- $('#apps-search').keyup(function (event) {
- if ( event.which == 13 ) {
- event.preventDefault();
- goToFirstMenuItem();
- } else {
- performSearch();
- }
-
- });
-
- $('#apps-search-clear').click(function () {
- $('#apps-search').val("");
- performSearch();
- });
- });
-
- $.ajax('../dhis-web-commons/menu/getModules.action').success(function (data) {
- if (typeof data.modules === 'object') {
- menu.addMenuItems(data.modules);
- }
- }).error(function () {
- //TODO: Give user feedback for failure to load items
- //TODO: Translate this error message
- var error_template = '<li class="app-menu-error"><a href="' + window.location.href +'">Unable to load your apps, click to refresh</a></li>';
- $('#' + selector).addClass('app-menu').html('<ul>' + error_template + '</ul>');
- $('#appsDropDown .menuDropDownBox').html(error_template);
- });
-
- /**
- * Event handler for the sort order box
- */
- $('#menuOrderBy').change(function (event) {
- var orderBy = $(event.target).val();
-
- dhis2.menu.displayOrder = orderBy;
-
- renderMenu();
- });
-
- /**
- * Check if we need to fix columns when the window resizes
- */
- $(window).resize(twoColumnRowFix);
-
- /**
- * Adds a scrolling mechanism that makes space for the scrollbar and shows/hides the more apps button
- */
- $('.menu-drop-down-scroll').scroll(function (event) {
- var self = $(this);
-
- if (self.scrollTop() < 10) {
- self.parent().css('width', '360px');
- self.parent().parent().css('width', '360px');
- } else {
- if (self.innerHeight() === 375 ) {
- self.parent().css('width', '384px');
- self.parent().parent().css('width', '384px');
- }
- }
-
- });
-
- function executeDropDownHooks(dropDownId) {
- var hooks = dropDownHooks.get(dropDownId);
- hooks.forEach(function (hook) {
- hook.call('#' + dropDownId);
- });
- }
-
- function showDropDown( id )
- {
- var newDropDownId = "#" + id,
- position = $(newDropDownId + '_button').position();
-
- cancelHideDropDownTimeout();
-
- $(newDropDownId).css('position', 'absolute');
- $(newDropDownId).css('top', '55px');
- $(newDropDownId).css('left', Math.ceil(position.left - Math.ceil(parseInt($(newDropDownId).innerWidth(), 10) - 108)) + 'px');
-
- if ( dropDownId != newDropDownId ) {
- hideDropDown();
-
- dropDownId = newDropDownId;
-
- $( dropDownId ).show();
- }
-
- executeDropDownHooks(id);
- }
-
- function hideDropDown() {
- if ( dropDownId ) {
- if ($( dropDownId ).attr( 'data-clicked-open' ) === 'true') {
- return;
- }
- $( dropDownId ).hide();
-
- dropDownId = null;
- }
- }
-
- function hideDropDownTimeout() {
- closeTimer = window.setTimeout( hideDropDown, menuTimeout );
- }
-
- function cancelHideDropDownTimeout() {
- if ( closeTimer ) {
- window.clearTimeout( closeTimer );
-
- closeTimer = null;
- }
- }
-
- // Set show and hide drop down events on top menu
- $( "#appsMenuLink" ).hover(function() {
- showDropDown( "appsDropDown" );
- }, function() {
- hideDropDownTimeout();
- });
-
- $( "#profileMenuLink" ).hover(function() {
- showDropDown( "profileDropDown" );
- }, function() {
- hideDropDownTimeout();
- });
-
- $( "#appsDropDown, #profileDropDown" ).hover(function() {
- cancelHideDropDownTimeout();
- }, function() {
- hideDropDownTimeout();
- });
-
-
- $('.drop-down-menu-link').get().forEach(function (element, index, elements) {
- var id = $(element).parent().attr('id'),
- dropdown_menu = $('div#' + id.split('_')[0]);
-
- function closeAllDropdowns() {
- $('.app-menu-dropdown').each(function () {
- $(this).attr('data-clicked-open', 'false');
- $(this).hide();
- });
- hideDropDown();
- }
-
- $(element).click(function () {
- return function () {
- var thisDropDownStatus = $(dropdown_menu).attr('data-clicked-open');
- closeAllDropdowns();
-
- if (thisDropDownStatus === 'true') {
- $(dropdown_menu).attr('data-clicked-open', 'false');
- } else {
- $(dropdown_menu).attr('data-clicked-open', 'true');
- showDropDown(dropdown_menu.attr('id'));
- }
- }
- }());
- });
-
- $(window).resize(function () {
- $('.app-menu-dropdown').get().forEach(function (element, index, elements) {
- var newDropDownId = '#' + $(element).attr('id'),
- position = $(newDropDownId + '_button').position();
-
- $(newDropDownId).css('position', 'absolute');
- $(newDropDownId).css('top', '55px');
- $(newDropDownId).css('left', Math.ceil(position.left - Math.ceil(parseInt($(newDropDownId).innerWidth(), 10) - 108)) + 'px');
- });
- });
-
- $('.apps-scroll-up').click(function (event) {
- var scrollDistance = 330,
- scrollTop = $('.menu-drop-down-scroll').scrollTop();
-
- event.preventDefault();
-
- $('.menu-drop-down-scroll').animate({
- scrollTop: scrollTop - scrollDistance
- }, 200);
- });
-
- $('.apps-scroll-down').click(function (event) {
- var scrollDistance = 330,
- scrollTop = $('.menu-drop-down-scroll').scrollTop();
-
- event.preventDefault();
-
- if (scrollTop < 110) {
- scrollDistance += 40;
- }
- $('.menu-drop-down-scroll').animate({
- scrollTop: scrollTop + scrollDistance
- }, 200);
- });
-
- });
-
-})(jQuery, dhis2.menu);
+ return searchMatches;
+ }
+
+ if (typeof preLoadedData === 'object') {
+ that.addMenuItems(preLoadedData);
+ }
+
+ return that;
+ };
+
+ //Expose the fixUrl method so we can use externally
+ dhis2.menu.fixUrlIfNeeded = fixUrlIfNeeded;
+})(dhis2 = dhis2 || {});
=== added file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.manager.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.manager.js 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.manager.js 2014-06-11 20:02:19 +0000
@@ -0,0 +1,191 @@
+"use strict";
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * Created by mark on 11/06/14.
+ */
+/**
+ * Created by Mark Polak on 28/01/14.
+ *
+ * @description jQuery part of the menu
+ *
+ * @see jQuery (http://jquery.com)
+ * @see jQuery Template Plugin (http://github.com/jquery/jquery-tmpl)
+ */
+(function ($, menu, undefined) {
+ var markup = '',
+ selector = 'appsMenu';
+
+ markup += '<li data-id="${id}" data-app-name="${name}" data-app-action="${defaultAction}">';
+ markup += ' <a href="${defaultAction}" class="app-menu-item">';
+ markup += ' <img src="${icon}" onError="javascript: this.onerror=null; this.src = \'../icons/program.png\';">';
+ markup += ' <span>${name}</span>';
+ markup += ' <div class="app-menu-item-description"><span class="bold">${name}</span><i class="fa fa-arrows"></i><p>${description}</p></div>';
+ markup += ' </a>';
+ markup += '</li>';
+
+ $.template('appMenuItemTemplate', markup);
+
+ function renderAppManager(selector) {
+ var apps = menu.getOrderedAppList();
+ $('#' + selector).html('');
+ $('#' + selector).append($('<ul></ul><hr class="app-separator">').addClass('ui-helper-clearfix'));
+ $('#' + selector).addClass('app-menu');
+ $.tmpl( "appMenuItemTemplate", apps).appendTo('#' + selector + ' ul');
+
+ //Add favorites icon to all the menu items in the manager
+ $('#' + selector + ' ul li').each(function (index, item) {
+ $(item).children('a').append($('<i class="fa fa-bookmark"></i>'));
+ });
+
+ twoColumnRowFix();
+ }
+
+ /**
+ * Saves the given order to the server using jquery ajax
+ *
+ * @param menuOrder {Array}
+ */
+ function saveOrder(menuOrder) {
+ if (menuOrder.length !== 0) {
+ //Persist the order on the server
+ $.ajax({
+ contentType:"application/json; charset=utf-8",
+ data: JSON.stringify(menuOrder),
+ dataType: "json",
+ type:"POST",
+ url: "../api/menu/"
+ }).success(function () {
+ //TODO: Give user feedback for successful save
+ }).error(function () {
+ //TODO: Give user feedback for failure to save
+ });
+ }
+ }
+
+ /**
+ * Resets the app blocks margin in case of a resize or a sort update.
+ * This function adds a margin to the 9th element when the screen is using two columns to have a clear separation
+ * between the favorites and the other apps
+ *
+ * @param event
+ * @param ui
+ */
+ function twoColumnRowFix(event, ui) {
+ var self = $('.app-menu ul'),
+ elements = $(self).find('li:not(.ui-sortable-helper)');
+
+ elements.each(function (index, element) {
+ $(element).css('margin-right', '0px');
+ if ($(element).hasClass('app-menu-placeholder')) {
+ $(element).css('margin-right', '10px');
+ }
+ //Only fix the 9th element when we have a small enough screen
+ if (index === 8 && (self.width() < 808)) {
+ $(element).css('margin-right', '255px');
+ }
+ });
+
+ }
+
+ /**
+ * Render the menumanager and the dropdown menu and attach the update handler
+ */
+ //TODO: Rename this as the name is not very clear to what it does
+ function renderMenu() {
+ var options = {
+ placeholder: 'app-menu-placeholder',
+ connectWith: '.app-menu ul',
+ update: function (event, ui) {
+ var reorderedApps = $("#" + selector + " ul"). sortable('toArray', {attribute: "data-id"});
+
+ menu.updateOrder(reorderedApps);
+ menu.save(saveOrder);
+ },
+ sort: twoColumnRowFix,
+ tolerance: "pointer",
+ cursorAt: { left: 55, top: 30 }
+ };
+
+ renderAppManager(selector);
+
+ $('.app-menu ul').sortable(options).disableSelection();
+ }
+
+ menu.subscribe(renderMenu);
+
+ /**
+ * jQuery events that communicate with the web api
+ * TODO: Check the urls (they seem to be specific to the dev location atm)
+ */
+ $(function () {
+ /**
+ * Event handler for the sort order box
+ */
+ $('#menuOrderBy').change(function (event) {
+ var orderBy = $(event.target).val();
+
+ menu.displayOrder = orderBy;
+
+ renderMenu();
+ });
+
+ /**
+ * Check if we need to fix columns when the window resizes
+ */
+ $(window).resize(twoColumnRowFix);
+
+ $('.drop-down-menu-link').get().forEach(function (element, index, elements) {
+ var id = $(element).parent().attr('id'),
+ dropdown_menu = $('div#' + id.split('_')[0]);
+
+ function closeAllDropdowns() {
+ $('.app-menu-dropdown').each(function () {
+ $(this).attr('data-clicked-open', 'false');
+ $(this).hide();
+ });
+ hideDropDown();
+ }
+
+ $(element).click(function () {
+ return function () {
+ var thisDropDownStatus = $(dropdown_menu).attr('data-clicked-open');
+ closeAllDropdowns();
+
+ if (thisDropDownStatus === 'true') {
+ $(dropdown_menu).attr('data-clicked-open', 'false');
+ } else {
+ $(dropdown_menu).attr('data-clicked-open', 'true');
+ showDropDown(dropdown_menu.attr('id'));
+ }
+ }
+ }());
+ });
+ });
+
+})(jQuery, dhis2.menu.mainAppMenu.menuItems);
=== added file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.ui.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.ui.js 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.menu.ui.js 2014-06-12 23:12:59 +0000
@@ -0,0 +1,1057 @@
+"use strict";
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * Created by Mark Polak on 28/01/14.
+ */
+(function (dhis2menu, settings, undefined) {
+
+ var jqLite = undefined, //Local jQuery variable to use for checking dependencies and switching jqLite and jQuery
+ templates = {},
+ cssDefaults = {},
+ getBaseUrl = (function () {
+ var href = window.location.origin;
+ return function () {
+ var urlParts = href.split("/"),
+ baseUrl;
+
+ if (settings.baseUrl === undefined) {
+ return "..";
+ }
+
+ if (typeof settings.baseUrl !== "string") {
+ throw new TypeError("Dhis2 settings: baseUrl should be a string");
+ }
+
+ //Check if there is a filename at the end of the current url
+ //if so remove it and join the parts else just join the href and the base url
+ if (urlParts[urlParts.length - 1] === "") {
+ urlParts.pop();
+ urlParts.push(dhis2.settings.baseUrl);
+ baseUrl = urlParts.join('/');
+ } else {
+ baseUrl = href + '/' + dhis2.settings.baseUrl;
+ }
+ return baseUrl;
+ }
+ })();
+
+ cssDefaults = {
+ ulWrapId: "menuLinkArea",
+ aMenuLinkClasses: "menu-link drop-down-menu-link"
+ }
+
+ templates.itemItemplate = '' +
+ '<li data-id="{{id}}" data-app-name="{{name}}" data-app-action="{{baseUrl}}{{defaultAction}}">' +
+ '<a href="{{baseUrl}}{{defaultAction}}" class="app-menu-item">' +
+ '<img src="{{baseUrl}}{{icon}}" onError="javascript: this.onerror=null; this.src = \'' + getBaseUrl() + '/icons/program.png\';">' +
+ '<span>{{name}}</span>' +
+ '<div class="app-menu-item-description"><span class="bold">{{name}}</span><i class="fa fa-arrows"></i><p>{{description}}</p></div>' +
+ '</a>' +
+ '</li>';
+
+
+ templates.menuLink = '<li id="{{id}}_button">' +
+ '<a id="{{id}}Link" class="{{classes}}"><i class="fa fa-{{iconName}}"></i>{{menuItemName}}</a>' +
+ '<div class="app-menu-dropdown-wrap">' +
+ '<div class="menuDropDownArea app-menu-dropdown appsMenuLink_menu ui-front">' +
+ '<div class="caret-up-border"></div><div class="caret-up-background"></div>' +
+ '<ul class="menuDropDownBox">{{menuItems}}</ul>' +
+ '<div class="menu-drop-down-buttons"></div>' +
+ '</div>' +
+ '</div>' +
+ '</li>';
+
+ templates.menuLinkWithScroll = '<li id="{{id}}_button">' +
+ '<a id="{{id}}Link" class="{{classes}}"><i class="fa fa-{{iconName}}"></i>{{menuItemName}}</a>' +
+ '<div class="app-menu-dropdown-wrap">' +
+ '<div class="menuDropDownArea app-menu-dropdown appsMenuLink_menu ui-front">' +
+ '<div class="caret-up-border"></div><div class="caret-up-background"></div>' +
+ '<div class="menu-drop-down-wrap">' +
+ '<div class="menu-drop-down-scroll">' +
+ '<ul class="menuDropDownBox">{{menuItems}}</ul>' +
+ '</div>' +
+ '</div>' +
+ '<div class="menu-drop-down-buttons">' +
+ '<div class="apps-menu-bottom-button apps-scroll apps-scroll-up"><a class="fa fa-caret-up" href="#"></a></div>' +
+ '<div class="apps-menu-bottom-button apps-scroll apps-scroll-down"><a class="fa fa-caret-down" href="#"></a></div>' +
+ '</div>' +
+ '</div>' +
+ '</div>' +
+ '</li>';
+
+ templates.search = '<div class="apps-search-wrap">' +
+ '<input class="apps-search" type="text" placeholder="{{search_apps}}">' +
+ '<span class="apps-search-clear fa fa-times-circle"></span>' +
+ '</div>';
+
+ templates.extraLink = '<div class="apps-menu-bottom-button apps-menu-more"><a href="{{url}}">{{text}}</a></div>';
+
+ var template, defaultMenuUi, searchUi, linkButtonUi, scrollUi, shortCutUi, keys;
+
+ keys = {
+ ctrl: 17,
+ enter: 13,
+ slash: 191,
+ backslash: 220,
+ arrowLeft: 37,
+ arrowUp: 38,
+ arrowRight: 39,
+ arrowDown: 40,
+ m: 77,
+ comma: 188,
+ dot: 190,
+ isArrowKey: function (keyCode) {
+ return (keyCode === keys.arrowRight ||
+ keyCode === keys.arrowLeft ||
+ keyCode === keys.arrowDown ||
+ keyCode === keys.arrowUp);
+ }
+ }
+
+ /*
+ * Check for what type of jquery/jqLite we are using and assign it to jqLite.
+ * We name it jqLite so that whoever maintains this code is not confused by the selectors available
+ * Please note that this jqLite is the angular version of jqLite and this does not contain the full jqLite api but
+ * is a subset of.
+ *
+ * @see https://docs.angularjs.org/api/ng/function/angular.element
+ */
+ if (typeof angular !== 'undefined') {
+ jqLite = angular.element;
+ } else {
+ if (typeof jQuery !== 'undefined') {
+ jqLite = jQuery;
+ }
+ }
+
+ /**
+ * Utility function to check if an object is a function
+ *
+ * @param obj Value that should be checked
+ * @returns {boolean} Returns true when the passed object is a function
+ */
+ function isFunction(obj) {
+ return Object.prototype.toString.call(obj) == '[object Function]';
+ }
+
+ /**
+ * Load data from a dataUrl and return the modules that were found in that response
+ * Fires a http request for json content and takes the {modules} parameter from the returned json object
+ *
+ * @param {String} dataUrl Url of the data to be requested
+ * @param {Function} callback Callback to be fired when the data is recieved
+ * @param {Object} extra Extra information that gets passed to the callback function
+ * along side of the modules that are found.
+ */
+ function loadDataFromUrl(dataUrl, callback, extra) {
+ var http, url;
+
+ http = new XMLHttpRequest();
+ url = getBaseUrl() + dataUrl;
+
+ http.open("GET", url, true);
+
+ //Send the proper header information along with the request
+ http.setRequestHeader("Content-type", "application/json; charset=utf-8");
+
+ http.onreadystatechange = function() {//Call a function when the state changes.
+ if(http.readyState == 4 && http.status == 200) {
+ if (typeof callback === 'function') {
+ callback(JSON.parse(http.responseText).modules, extra);
+ }
+ } else {
+ /*
+ //TODO: Give user feedback for failure to load items
+ //TODO: Translate this error message
+ var error_template = '<li class="app-menu-error"><a href="' + window.location.href +'">Unable to load your apps, click to refresh</a></li>';
+ $('#' + selector).addClass('app-menu').html('<ul>' + error_template + '</ul>');
+ $('#appsDropDown .menuDropDownBox').html(error_template);
+ */
+ }
+ }
+ http.send();
+ }
+
+ /**
+ * Creates a template object with methods to find and parse templates. This is
+ * used for managing menu templates within the various menu addons.
+ *
+ * @param templates
+ * @returns {}
+ */
+ template = function (templates) {
+ var template = {};
+
+ if (templates === undefined)
+ templates = {};
+
+ function findTemplateByName(templateName) {
+ if (templates[templateName])
+ return templates[templateName];
+
+ //Throw error when template does not exist
+ console.error("Template with name: " + templateName + " does not exist");
+ }
+
+ /**
+ * Parses a template
+ *
+ * @param {String} templateName The name of the template to be parsed
+ * @param {Object} data This is an object that holds the data to be placed into the placeholders
+ * @returns {String} Parsed template
+ */
+ template.parse = function (templateName, data) {
+ var regex = /\{\{([A-z]+?)\}\}/,
+ match,
+ template = findTemplateByName(templateName);
+
+ while(match = regex.exec(template)) {
+ template = template.replace('{{' + match[1] + '}}', data[match[1]] || '');
+ }
+
+ return template;
+ }
+
+ /**
+ * Gets a "raw" template. This returns the template as it was saved, without parsing it.
+ * @param {String} name The name of the template
+ * @returns {String}
+ */
+ template.get = function (name) {
+ if (templates[name] === undefined) {
+ console.error("Template " + name + " does not exist");
+ }
+ return templates[name];
+ }
+
+ /**
+ * Adds a template to the template cache
+ *
+ * A Template may contain placeholders. These placeholders are replaced with values when
+ * the template is parsed.
+ *
+ * Place holders are defined between double curly brackets like for example {{id}}.
+ * When parsing a template with this place holder the parse method will take the "id" property
+ * from the data object and place it instead of the placeholder.
+ *
+ * @param {String} name The name of the template, and how to identify it
+ * @param {String} template The template itself (This can be any type of string/html, possibly with placeholders)
+ */
+ template.add = function (name, template) {
+ if (templates[name]) {
+ console.error("Template not allowed to be overridden using the add method, use the replace method instead");
+ }
+ templates[name] = template;
+ }
+
+ /**
+ * Replace an already existing template with a different one
+ *
+ * @param {String} name The name of the template, and how to identify it
+ * @param {String} template The template itself (This can be any type of string/html, possibly with placeholders)
+ */
+ template.replace = function (name, template) {
+ if (templates[name] === undefined) {
+ console.error("No template to be replaced, use the add method to add templates")
+ }
+ templates[name] = template;
+ }
+
+ return template;
+ }
+
+ /**
+ * Creates an error object with that has the passed in message
+ *
+ * @param message
+ * @returns {MenuError}
+ * @constructor
+ */
+ function MenuError (message) {
+ var MenuError = function () {},
+ error;
+
+ MenuError.prototype = new Error;
+
+ error = new MenuError();
+
+ error.message = message;
+
+ error.toString = function () {
+ return "MenuError: " + this.message + " \n";
+ }
+
+ return error;
+ }
+
+ /**
+ * Creates a menu object with the menuBase as a prototype
+ *
+ * @param menuBase
+ * @returns {Menu}
+ */
+ function createMenu (menuBase) {
+ var Menu = function () {},
+ menu;
+
+ /**
+ * When the function is called with an empty menuBase
+ * we create a default menuBase with some essential variables
+ */
+ if (menuBase === undefined) {
+ menuBase = {
+ renderers: [],
+ eventsHandlers: [],
+ name: "",
+ hooks: {
+ open: [],
+ close: []
+ }
+ };
+ menuBase.hooks.call = function (name) {
+ if (menuBase.hooks[name]) {
+ menuBase.hooks[name].forEach(function (callback) {
+ if (isFunction(callback)) {
+ callback.apply(name);
+ }
+ });
+ }
+ }
+ }
+
+ Menu.prototype = menuBase;
+ menu = new Menu();
+
+ //TODO: Render function now gets added to all objects (Preferably we only need one)
+ menu.render = function (menuItems) {
+ jqLite(document).ready(function () {
+ menuBase.renderers.forEach(function (renderFunction) {
+ if (isFunction(renderFunction)) {
+ renderFunction(menuItems);
+ }
+ });
+ //Add the event handlers only once
+ menuBase.eventsHandlers.forEach(function (eventFunction) {
+ if (isFunction(eventFunction)) {
+ eventFunction(document.querySelector('#' + menu.name + "_button"));
+ }
+ });
+ });
+ };
+
+ return menu;
+ }
+
+ /**
+ * Menu with default functionality
+ *
+ * @returns {Menu}
+ */
+ defaultMenuUi = function (name, data, icon, container) {
+ var defaultMenu = createMenu(),
+ currentSelectedId = undefined;
+
+ defaultMenu.template = template();
+
+ defaultMenu.name = name;
+ defaultMenu.ajax = false;
+ defaultMenu.icon = icon;
+ defaultMenu.container = container;
+
+ if (typeof data === "string") {
+ //TODO: Implement this
+ loadDataFromUrl(data, function (data) {
+ defaultMenu.menuItems.addMenuItems(data)
+ });
+ defaultMenu.menuItems = dhis2.menu(name);
+ } else {
+ defaultMenu.menuItems = dhis2.menu(name, data);
+ }
+
+ defaultMenu.template.add('menuStructure', '<ul id="{{id}}"></ul>');
+ defaultMenu.template.add('linkItem', templates.menuLink);
+ defaultMenu.template.add('menuItem', templates.itemItemplate);
+
+ defaultMenu.isOpen = function () {
+ var dropdownElement = jqLite(document.querySelector("#" + defaultMenu.name + "_button div.app-menu-dropdown-wrap")),
+ display = jqLite(dropdownElement).css("display");
+ if (display === 'none') {
+ return false;
+ }
+ return true;
+ }
+
+ defaultMenu.isClosed = function () {
+ return ! defaultMenu.isOpen();
+ }
+
+ defaultMenu.open = function (hover) {
+ var dropdownElement = jqLite(document.querySelector("#" + defaultMenu.name + "_button div.app-menu-dropdown-wrap"));
+
+ //Set the dropdown position
+ jqLite(dropdownElement).css('left', defaultMenu.getDropDownPosition() + 'px');
+ dropdownElement.css('display', 'block');
+
+ if (! hover) {
+ dropdownElement.attr("data-display-clicked", "true");
+ }
+ defaultMenu.hooks.call('open');
+ }
+
+ defaultMenu.close = function (hover) {
+ var dropdownElement = jqLite(document.querySelector("#" + defaultMenu.name + "_button div.app-menu-dropdown-wrap"));
+
+ dropdownElement.css('display', 'none');
+ if ( ! hover) {
+ dropdownElement.attr("data-display-clicked", "false");
+ }
+ defaultMenu.hooks.call('close');
+ }
+
+ defaultMenu.closeAll = function () {
+ var menuDropDowns = document.querySelectorAll("#" + defaultMenu.container + " div.app-menu-dropdown-wrap");
+ jqLite(menuDropDowns).css('display', 'none');
+ jqLite(menuDropDowns).attr("data-display-clicked", "false");
+ }
+
+ defaultMenu.setCurrentId = function (id) {
+ currentSelectedId = id;
+ }
+
+ defaultMenu.getCurrentId = function () {
+ return currentSelectedId;
+ }
+
+ defaultMenu.goToMenuItem = function (menuElement) {
+ var link, url;
+
+ if (menuElement === undefined)
+ return;
+
+ link = menuElement.querySelector('a');
+ url = jqLite(link).attr('href');
+
+ //TODO: Check if it is an actual url?
+ if (url) {
+ window.location = url;
+ }
+ }
+
+ defaultMenu.renderMenuItems = function (menuItems) {
+ var result = '';
+ //Parse item template once for each of the menu items
+ menuItems.forEach(function (menuItem) {
+ result += defaultMenu.template.parse('menuItem', {
+ "id": menuItem.id,
+ "name": menuItem.name,
+ "defaultAction": menuItem.defaultAction,
+ "icon": menuItem.icon
+ });
+ });
+ return result;
+ }
+
+ defaultMenu.getDropDownPosition = function () {
+ var menuElement = document.querySelector("#" + defaultMenu.name + "_button"),
+ dropdownElement = jqLite(menuElement.querySelector("div.app-menu-dropdown-wrap")),
+ dropdownPosition;
+
+ dropdownElement.css('display', 'block');
+
+ // Get the dropdown width and position
+ defaultMenu.dropdownWidth = dropdownElement[0].offsetWidth;
+ defaultMenu.linkPositionX = menuElement.offsetLeft;
+
+ // Calculate the dropdown position x
+ dropdownPosition = defaultMenu.linkPositionX - (defaultMenu.dropdownWidth - menuElement.offsetWidth);
+
+ //Hide the dropdown element
+ dropdownElement.css('display', 'none');
+
+ return dropdownPosition;
+ }
+
+ defaultMenu.renderers.push(function (menuData) {
+ var linkItem, menuItems;
+
+ menuItems = defaultMenu.renderMenuItems(menuData.getApps());
+
+ //Build the menu item and dropdown
+ linkItem = defaultMenu.template.parse('linkItem', {
+ "id": defaultMenu.name,
+ "iconName": defaultMenu.icon,
+ "menuItemName": menuData.name,
+ "classes": cssDefaults.aMenuLinkClasses,
+ "menuItems": menuItems
+ });
+
+ //Create menu wrapper if it does not exist
+ if (document.querySelector('#' + defaultMenu.container + ' ul') === null) {
+ jqLite(document.querySelector('#' + defaultMenu.container)).append(
+ defaultMenu.template.parse('menuStructure', {"id": cssDefaults.ulWrapId})
+ )
+ }
+
+ //Add the linkItem to the menu
+ jqLite(document.querySelector('#' + defaultMenu.container + ' ul')).append(linkItem);
+ });
+
+ defaultMenu.eventsHandlers.push(function (menuElement) {
+ var dropdownElement = jqLite(menuElement.querySelector("div.app-menu-dropdown-wrap"));
+
+ //Add click to show dropdown event
+ jqLite(menuElement.querySelector("a.drop-down-menu-link")).on("click", function () {
+ if (dropdownElement.attr("data-display-clicked") === "true") {
+ defaultMenu.close();
+ } else {
+ defaultMenu.closeAll();
+ defaultMenu.open();
+ }
+ });
+
+ //Hover event
+ jqLite(menuElement).on('mouseenter', function() {
+ defaultMenu.open(true);
+ });
+ jqLite(menuElement).on('mouseleave', function() {
+ if (dropdownElement.attr('data-display-clicked') === "true") {
+ return;
+ }
+ defaultMenu.close(true);
+ });
+
+ jqLite(window).on('resize', function () {
+ defaultMenu.closeAll();
+ });
+ });
+
+ defaultMenu.menuItems.subscribe(defaultMenu.render, true);
+ defaultMenu.menuItems.subscribe(function (menu) {
+ var menuElementList = document.querySelector("#" + defaultMenu.name + "_button ul.menuDropDownBox"),
+ menuItemsHtml;
+
+ if (menuElementList === null)
+ return;
+
+ menuItemsHtml = defaultMenu.renderMenuItems(menu.getApps());
+
+ jqLite(menuElementList.querySelectorAll("li")).remove();
+ jqLite(menuElementList).append(menuItemsHtml);
+ defaultMenu.setCurrentId(undefined);
+ });
+
+ return createMenu(defaultMenu);
+ }
+
+ scrollUi = function (menu) {
+ var scrollMenu = menu;
+
+ scrollMenu.template.replace('linkItem', templates.menuLinkWithScroll);
+
+ scrollMenu.eventsHandlers.push(function (menuElement) {
+ var scrollElement = menuElement.querySelector('div.menu-drop-down-scroll'),
+ scrollUpElement = menuElement.querySelector('div.apps-scroll-up'),
+ scrollDownElement = menuElement.querySelector('div.apps-scroll-down');
+
+ jqLite(scrollElement).on('scroll', function () {
+ if (scrollElement.scrollTop < 10) {
+ scrollMenu.menuWidth = 360;
+ } else {
+ scrollMenu.menuWidth = 384;
+ }
+ jqLite(scrollElement).parent().css('width', scrollMenu.menuWidth + 'px');
+ jqLite(scrollElement).parent().parent().css('width',scrollMenu.menuWidth + 'px');
+ });
+
+ jqLite(scrollUpElement).on('click', function (event) {
+ event.preventDefault();
+ scrollElement.scrollTop = scrollElement.scrollTop - 330;
+ });
+
+ jqLite(scrollDownElement).on('click', function (event) {
+ var scrollDistance = 330;
+ event.preventDefault();
+
+ //TODO: We should only have to do this when there is a scrollbar
+ //Compensate on first scroll for searchbar
+ if (scrollElement.scrollTop === 0) {
+ scrollDistance += 40;
+ }
+
+ scrollElement.scrollTop = scrollElement.scrollTop + scrollDistance;
+ });
+ });
+
+ return createMenu(scrollMenu);
+ }
+
+ /**
+ * Adds search functionality to the passed menu
+ *
+ * @param menu
+ * @returns {Menu}
+ */
+ searchUi = function (menu) {
+ var searchMenu = menu,
+ rendered = false,
+ searchAppsText = '';
+
+ function performSearch(menuElement) {
+ var menuItemsHtml,
+ searchFor = jqLite(menuElement.querySelector(".apps-search")).val().toLowerCase(),
+ searchMatches,
+ menuElementList = menuElement.querySelector('ul.menuDropDownBox');
+
+ if (searchFor === '') {
+ jqLite(menuElement.querySelector(".apps-search-clear")).css("display", "none");
+ menuElement.querySelector(".apps-search").focus();
+ menuItemsHtml = searchMenu.renderMenuItems(searchMenu.menuItems.getApps());
+ } else {
+ jqLite(menuElement.querySelector(".apps-search-clear")).css("display", "block");
+ searchMatches = searchMenu.menuItems.search(searchFor);
+ menuItemsHtml = searchMenu.renderMenuItems(searchMatches);
+ }
+
+ jqLite(menuElementList.querySelectorAll('li')).remove();
+ jqLite(menuElementList).append(menuItemsHtml);
+ searchMenu.setCurrentId(undefined);
+ }
+
+ searchMenu.template.add('search', templates.search);
+
+ //Translate the search apps name
+ dhis2.translate.get(['app_search_placeholder'], function (translations) {
+ var searchBoxElement = document.querySelector('#' + searchMenu.name + "_button input.apps-search");
+
+ searchAppsText = translations.get('app_search_placeholder');
+ if (rendered === true) {
+ jqLite(searchBoxElement).attr('placeholder', searchAppsText);
+ }
+ });
+
+ searchMenu.renderers.push(function () {
+ var dropdownWrap = document.querySelector('#' + searchMenu.name + "_button div.menu-drop-down-scroll");
+ jqLite(dropdownWrap).prepend(searchMenu.template.parse('search', { search_apps: searchAppsText }));
+ rendered = true;
+ });
+
+ searchMenu.eventsHandlers.push(function (menuElement) {
+ var searchBoxElement = menuElement.querySelector("input.apps-search");
+
+ searchMenu.hooks.open.push(function () {
+ searchBoxElement.focus();
+ });
+
+ jqLite(searchBoxElement).on('keyup', function (event) {
+ //Filter the menu items
+ if ( ! keys.isArrowKey(event.which) &&
+ ! (event.which === keys.enter) &&
+ ! (event.which === keys.ctrl)) {
+ performSearch(menuElement);
+ }
+ });
+
+ jqLite(menuElement.querySelector(".apps-search-clear")).on('click', function () {
+ jqLite(menuElement.querySelector(".apps-search-clear")).css("display", "none");
+ jqLite(menuElement.querySelector(".apps-search")).val("");
+ menuElement.querySelector(".apps-search").focus();
+ performSearch(menuElement);
+ });
+ });
+
+ return createMenu(searchMenu);
+ }
+
+ linkButtonUi = function (menu) {
+ var linkButtonMenu = menu,
+ rendered = false;
+
+ linkButtonMenu.template.add('extraLink', templates.extraLink);
+
+ //Translate the link name
+ dhis2.translate.get([menu.extraLink.text], function (translations) {
+ menu.extraLink.text = translations.get(menu.extraLink.text);
+ if (rendered === true) {
+ //TODO change the class of this button to make it more general
+ jqLite(document.querySelector('#' + linkButtonMenu.name + 'div.apps-menu-bottom-button')).html(menu.extraLink.text);
+ }
+ });
+
+ linkButtonMenu.renderers.push(function () {
+ var buttonContainer = document.querySelector('#' + linkButtonMenu.name + "_button div.menu-drop-down-buttons");
+ menu.extraLink.url = dhis2.menu.fixUrlIfNeeded(menu.extraLink.url);
+ jqLite(buttonContainer).prepend(linkButtonMenu.template.parse('extraLink', menu.extraLink));
+ rendered = true;
+ });
+
+ return createMenu(linkButtonMenu);
+ }
+
+ shortCutUi = function (menu) {
+ var shortCutMenu = menu;
+
+ shortCutMenu.eventsHandlers.push(function (menuElement) {
+ var currentElement,
+ shortCutElements,
+ oldFocusedElement;
+
+ function changeCurrentSelected(currentElement) {
+
+ function animateScrollTo(scrollable, scrollto) {
+ var modifier = 2;
+ scrollto = scrollto - 49;
+
+ function scrollDown() {
+ if (scrollable.scrollTop >= scrollto || scrollable.offsetHeight + 49 === scrollable.scrollTop) {
+ return;
+ }
+ scrollable.scrollTop = scrollable.scrollTop + modifier;
+ setTimeout(scrollDown, 1);
+ }
+
+ function scrollUp() {
+ if (scrollable.scrollTop <= scrollto || 0 === scrollable.scrollTop)
+ return;
+ scrollable.scrollTop = scrollable.scrollTop - modifier;
+ setTimeout(scrollUp, 1);
+ }
+
+ if (scrollable.scrollTop > scrollto) {
+ scrollUp();
+ } else {
+ scrollDown();
+ }
+ }
+
+ jqLite(shortCutMenu.selectedElement).toggleClass("selected");
+ shortCutMenu.selectedElement = shortCutElements[currentElement];
+ jqLite(shortCutMenu.selectedElement).toggleClass("selected");
+
+ if (menuElement.querySelector("div.menu-drop-down-scroll")) {
+ animateScrollTo(menuElement.querySelector("div.menu-drop-down-scroll"), shortCutMenu.selectedElement.offsetTop);
+ }
+
+ shortCutMenu.setCurrentId(currentElement);
+ }
+
+ shortCutMenu.hooks.close.push(function () {
+ shortCutMenu.setCurrentId(undefined);
+ });
+
+ jqLite(document).on("keyup", function (event) {
+ /**
+ * Key combination using alt to control opening and closing
+ */
+ if (event.which === shortCutMenu.shortCutKey && event.ctrlKey) {
+ event.preventDefault();
+
+ if (shortCutMenu.isOpen()) {
+ shortCutMenu.close();
+ if (oldFocusedElement)
+ oldFocusedElement.focus();
+ } else {
+ oldFocusedElement = document.activeElement;
+ document.activeElement.blur();
+
+ shortCutMenu.closeAll();
+ shortCutMenu.open();
+ }
+ }
+ });
+
+ jqLite(menuElement.querySelectorAll('input')).on("keydown", function (event) {
+ if (keys.isArrowKey(event.which)) {
+ return false;
+ }
+ });
+
+ jqLite(document).on("keyup", function (event) {
+ var goToElement;
+
+ /**
+ * Calculate the number of positions we have available if we fill all the rows
+ * @returns {number}
+ */
+ function getPositionsNumber() {
+ return Math.ceil(shortCutElements.length / 3) * 3;
+ }
+
+ //Don't run anything when the menu is not open
+ if (shortCutMenu.isClosed()) {
+ return;
+ }
+
+ //Prevent default behavior for any of the bound keys when the menu is open
+ event.preventDefault();
+
+ //Get the menu elements available on the dom
+ shortCutElements = menuElement.querySelectorAll("ul.menuDropDownBox li");
+
+ /**
+ * Movement keys
+ */
+ if (keys.isArrowKey(event.which)) {
+ currentElement = shortCutMenu.getCurrentId();
+
+ event.preventDefault();
+
+ //When the first arrow button is pressed but there is no selected element use the first one
+ if (currentElement === undefined) {
+ currentElement = 0;
+ changeCurrentSelected(currentElement);
+ return;
+ }
+
+ if (event.which === keys.arrowRight) {
+ currentElement = currentElement + 1;
+ if (shortCutElements[currentElement] === undefined) {
+ currentElement = 0;
+ }
+ changeCurrentSelected(currentElement);
+ return;
+ }
+
+ if (event.which === keys.arrowLeft) {
+ currentElement = currentElement - 1;
+ if (shortCutElements[currentElement] === undefined) {
+ currentElement = shortCutElements.length - 1;
+ }
+ changeCurrentSelected(currentElement);
+ return;
+ }
+
+ if (event.which === keys.arrowDown) {
+ currentElement = currentElement + 3;
+ if (shortCutElements[currentElement] === undefined) {
+ if (currentElement >= shortCutElements.length) {
+ currentElement = currentElement % 3;
+ } else {
+ currentElement = currentElement - shortCutElements.length;
+ }
+ }
+ changeCurrentSelected(currentElement);
+ return;
+ }
+
+ //TODO: Clean up this code a bit as it's very confusing to what it does now.
+ if (event.which === keys.arrowUp) {
+ currentElement = currentElement - 3;
+ if (shortCutElements[currentElement] === undefined) {
+ //Jump to the last
+ if (!((shortCutElements.length % 3) === 0)) {
+ currentElement = getPositionsNumber() - (-currentElement);
+ if (shortCutElements[currentElement] === undefined) {
+ if (currentElement === -1)
+ currentElement = 0;
+ else
+ currentElement = currentElement - 3;
+ }
+ } else {
+ currentElement = shortCutElements.length - (-currentElement);
+ }
+ }
+ changeCurrentSelected(currentElement);
+ return;
+ }
+ }
+
+ /**
+ * Key to go to the selected menu item if no item is selected go to the first one
+ */
+ if (event.which === keys.enter) {
+ goToElement = shortCutElements[shortCutMenu.getCurrentId()];
+ if (goToElement === undefined) {
+ goToElement = shortCutElements[0];
+ }
+ shortCutMenu.goToMenuItem(goToElement);
+ }
+ });
+ });
+
+ return createMenu(shortCutMenu);
+ }
+
+ /*******************************************************************************************************************
+ * Dhis2 menu ui functions
+ ******************************************************************************************************************/
+
+ /*
+ * Create the object that we will expose (This gets attached onto the dhis2.menu global variable as dhis2.menu.ui
+ * Generally one will use just the ui version but if there is a case where the ui does not need to be used a
+ * different wrapper can be build around dhis2.menu as all the menu logic is contained in there and this ui wrapper
+ * just creates an instance of the dhis2.menu object for each of the menus that are created.
+ */
+ dhis2menu.ui = {};
+ dhis2menu.ui.createMenu = function (menuName, menuData, options) {
+ var menu;
+
+ if (typeof menuName !== "string")
+ throw MenuError("Menu name needs to be a string");
+
+ //menuData is not a string and does not have any items
+ if (typeof menuData !== "string" && menuData.length <= 0) {
+ throw MenuError("Menu should have data to present in an array or be a url to fetch data from");
+ }
+
+ //Sets default options if non have been given
+ if (options == undefined)
+ options = {};
+
+ menu = defaultMenuUi(
+ menuName,
+ menuData,
+ options['icon'] || 'th', //th is the default font-awesome icon we use for menus
+ options['container'] || 'dhisDropDownMenu'); //dhisDropDownMenu is the default container for the menu
+
+ if ( !! options['shortCut'] && keys[options['shortCut']]) {
+ menu.shortCutKey = keys[options['shortCut']];
+ menu = shortCutUi(menu);
+ }
+
+ if ( !! options['scrollable']) {
+ menu = scrollUi(menu);
+ }
+
+ if ( !! options['scrollable'] && !! options['searchable']) {
+ menu = searchUi(menu);
+ }
+
+ if (typeof options['extraLink'] === 'object' && options.extraLink['url'] && options.extraLink['text']) {
+ menu.extraLink = options['extraLink'];
+ menu = linkButtonUi(menu);
+ }
+
+ return menu;
+ }
+
+})(window.dhis2.menu = window.dhis2.menu || {}, dhis2.settings = dhis2.settings || {});
+
+/**
+ * End of menu ui code. The code below creates the menu with the default profile and apps menus
+ */
+(function () {
+ dhis2.menu.ui.initMenu = function () {
+ try {
+ dhis2.menu.ui.createMenu("profile", [
+ {
+ name: "settings",
+ namespace: "/dhis-web-commons-about",
+ defaultAction: "../dhis-web-commons-about/userSettings.action",
+ icon: "../icons/usersettings.png",
+ description: ""
+ },
+ {
+ name: "profile",
+ namespace: "/dhis-web-commons-about",
+ defaultAction: "../dhis-web-commons-about/showUpdateUserProfileForm.action",
+ icon: "../icons/function-profile.png",
+ description: ""
+ },
+ {
+ name: "account",
+ namespace: "/dhis-web-commons-about",
+ defaultAction: "../dhis-web-commons-about/showUpdateUserAccountForm.action",
+ icon: "../icons/function-account.png",
+ description: ""
+ },
+ {
+ name: "help",
+ namespace: "/dhis-web-commons-about",
+ defaultAction: "../dhis-web-commons-about/help.action",
+ icon: "../icons/function-account.png",
+ description: ""
+ },
+ {
+ name: "log_out",
+ namespace: "/dhis-web-commons-about",
+ defaultAction: "../dhis-web-commons-security/logout.action",
+ icon: "../icons/function-log-out.png",
+ description: ""
+ },
+ {
+ name: "about_dhis2",
+ namespace: "/dhis-web-commons-about",
+ defaultAction: "../dhis-web-commons-about/about.action",
+ icon: "../icons/function-about-dhis2.png",
+ description: ""
+ }
+ ],
+ {
+ icon: "user",
+ shortCut: "comma"
+ }
+ );
+
+ dhis2.menu.mainAppMenu = dhis2.menu.ui.createMenu("applications",
+ "/dhis-web-commons/menu/getModules.action",
+ {
+ searchable: true,
+ scrollable: true,
+ extraLink: {
+ text: 'more_applications',
+ url: '../dhis-web-commons-about/modules.action'
+ },
+ shortCut: "m"
+ }
+ );
+
+ } catch (e) {
+ if (console && console.error)
+ console.error(e.message, e.stack);
+ }
+ }
+
+ if (window['angular']) {
+
+ /**
+ * Angular directive for the menu.
+ */
+ angular.module('d2Menu', [])
+ /**
+ * The directive places a div element with the dhisDropDownMenu id and then calls the normal menu
+ * init method to run all the normal javascript code.
+ */
+ .directive('d2Menu', [function () {
+ return {
+ restrict: 'A',
+ replace: true,
+ template: '<div id="dhisDropDownMenu"></div>',
+ //TODO: This might not be proper use of a controller
+ controller: function () {
+ dhis2.menu.ui.initMenu();
+ }
+ }
+ }]);
+
+ } else {
+ //If there is no angular we just run our normal init function to find tags ourselves
+ dhis2.menu.ui.initMenu();
+ }
+
+})();
\ No newline at end of file
=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.translate.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.translate.js 2014-04-14 02:24:15 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.translate.js 2014-05-12 08:02:12 +0000
@@ -34,18 +34,39 @@
/**
* Created by Mark Polak on 28/01/14.
- *
- * @see jQuery (http://jquery.com)
- * @see Underscore.js (http://underscorejs.org)
*/
-(function ($, _, translate, undefined) {
+(function (translate, undefined) {
var translationCache = {
- get: function (key) {
- if (this.hasOwnProperty(key))
- return this[key];
- return key;
- }
- };
+ get: function (key) {
+ if (this.hasOwnProperty(key))
+ return this[key];
+ return key;
+ }
+ },
+ getBaseUrl = (function () {
+ var href = window.location.origin;
+ return function () {
+ var urlParts = href.split("/"),
+ baseUrl;
+
+ if (dhis2.settings === undefined || dhis2.settings.baseUrl === undefined) {
+ return "..";
+ }
+
+ if (typeof dhis2.settings.baseUrl !== "string") {
+ throw new TypeError("Dhis2 settings: baseUrl should be a string");
+ }
+
+ if (urlParts[urlParts.length - 1] !== "") {
+ baseUrl = href + '/' + dhis2.settings.baseUrl;
+ } else {
+ urlParts.pop();
+ urlParts.push(dhis2.settings.baseUrl);
+ baseUrl = urlParts.join('/');
+ }
+ return baseUrl;
+ }
+ })();
/**
* Adds translations to the translation cache (overrides already existing ones)
@@ -53,7 +74,13 @@
* @param translations {Object}
*/
function addToCache(translations) {
- translationCache = _.extend(translationCache, translations);
+ var translationIndex;
+
+ for (translationIndex in translations) {
+ if (typeof translationIndex === 'string' && translationIndex !== 'get') {
+ translationCache[translationIndex] = translations[translationIndex];
+ }
+ }
}
/**
@@ -64,18 +91,23 @@
* @param callback {function}
*/
function getTranslationsFromServer(translateKeys, callback) {
- $.ajax({
- url:"../api/i18n",
- type:"POST",
- data: JSON.stringify(translateKeys),
- contentType:"application/json; charset=utf-8",
- dataType:"json"
- }).success(function (data) {
- addToCache(data);
+ var http = new XMLHttpRequest();
+ var url = getBaseUrl() + "/api/i18n";
+ var keysToTranslate = JSON.stringify(translateKeys);
+ http.open("POST", url, true);
+
+ //Send the proper header information along with the request
+ http.setRequestHeader("Content-type", "application/json; charset=utf-8");
+
+ http.onreadystatechange = function() {//Call a function when the state changes.
+ if(http.readyState == 4 && http.status == 200) {
+ addToCache(JSON.parse(http.responseText));
if (typeof callback === 'function') {
callback(translationCache);
}
- });
+ }
+ }
+ http.send(keysToTranslate);
}
/**
@@ -86,8 +118,7 @@
* @param callback {function}
*/
translate.get = function (translate, callback) {
- var translateKeys = [],
- key;
+ var translateKeys = [];
//Only ask for the translations that we do not already have
translate.forEach(function (text, index, translate) {
@@ -106,4 +137,4 @@
};
-})(jQuery, _, dhis2.translate);
+})(dhis2.translate);
=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/main.vm'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/main.vm 2014-05-24 08:58:21 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/main.vm 2014-06-04 14:37:34 +0000
@@ -80,6 +80,7 @@
<script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.appcache.js?_rev=$!{buildRevision}"></script>
<script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.translate.js?_rev=$!{buildRevision}"></script>
<script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.menu.js?_rev=$!{buildRevision}"></script>
+ <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.menu.ui.js?_rev=$!{buildRevision}"></script>
<script type="text/javascript" src="../dhis-web-commons/i18nJavaScript.action?_rev=$!{buildRevision}"></script>
<script type="text/javascript" src="../main.js?_rev=$!{buildRevision}"></script>
<script type="text/javascript" src="../request.js?_rev=$!{buildRevision}"></script>
@@ -107,79 +108,8 @@
<span id="headerText" onclick="window.location.href='../${startModule}/index.action'" style="cursor:pointer" title="$i18n.getString( 'view_home_page' )">
$encoder.htmlEncode( $applicationTitle )
</span>
-
- <ul id="menuLinkArea">
- <li id="profileDropDown_button">
- <a id="profileMenuLink" class="menu-link drop-down-menu-link">
- <i class="fa fa-user"></i>$i18n.getString( "profile" )
- </a>
- </li>
- <li id="appsDropDown_button">
- <a id="appsMenuLink" class="menu-link drop-down-menu-link">
- <i class="fa fa-th"></i>$i18n.getString( "applications" )
- </a>
- </li>
- </ul>
-
- <div id="appsDropDown" class="menuDropDownArea app-menu-dropdown appsMenuLink_menu ui-front" >
- <div class="caret-up-border"></div>
- <div class="caret-up-background"></div>
- <div class="menu-drop-down-wrap">
- <div class="menu-drop-down-scroll">
- <div class="apps-search-wrap">
- <input id="apps-search" class="apps-search" type="text" placeholder="$i18n.getString( "app_search_placeholder" )">
- <span id="apps-search-clear" class="fa fa-times-circle"></span>
- </div>
- <ul class="menuDropDownBox"><li class="menu-placeholder"><img src="../images/ajax-loader-bar.gif"></li></ul>
- </div>
- </div>
- <div class="apps-menu-bottom-button apps-menu-more"><a href="../dhis-web-commons-about/modules.action">$i18n.getString( "more_applications" )</a></div>
- <div class="apps-menu-bottom-button apps-scroll apps-scroll-up"><a class="fa fa-caret-up" href="#"></a></div>
- <div class="apps-menu-bottom-button apps-scroll apps-scroll-down"><a class="fa fa-caret-down" href="#"></a></div>
- </div>
-
- <div id="profileDropDown" class="menuDropDownArea app-menu-dropdown ui-helper-clearfix profileMenuLink_menu">
- <div class="caret-up-border"></div>
- <div class="caret-up-background"></div>
- <ul class="menuDropDownBox">
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-about/userSettings.action">
- <img src="../icons/usersettings.png" alt="$i18n.getString( "settings" )">
- <span>$i18n.getString( "settings" ) </span>
- </a>
- </li>
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-about/showUpdateUserProfileForm.action">
- <img src="../icons/function-profile.png" alt="$i18n.getString( "profile" )">
- <span>$i18n.getString( "profile" ) </span>
- </a>
- </li>
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-about/showUpdateUserAccountForm.action">
- <img src="../icons/function-account.png" alt="$i18n.getString( "account" )">
- <span>$i18n.getString( "account" ) </span>
- </a>
- </li>
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-about/help.action">
- <img src="../icons/function-help-center.png" alt="$i18n.getString( "help" )">
- <span>$i18n.getString( "help" ) </span>
- </a>
- </li>
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-security/logout.action">
- <img src="../icons/function-log-out.png" alt="$i18n.getString( "log_out" )">
- <span>$i18n.getString( "log_out" ) </span>
- </a>
- </li>
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-about/about.action">
- <img src="../icons/function-about-dhis2.png" alt="$i18n.getString( "about_dhis2" )">
- <span>$i18n.getString( "about_dhis2" ) </span>
- </a>
- </li>
- </ul>
- </div>
+
+ <div id="dhisDropDownMenu"></div>
<span id="showLeftBar">
<a href="javascript:dhis2.leftBar.showAnimated()" title="$i18n.getString( 'show_menu' )">
=== modified file 'dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/event-capture.appcache'
--- dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/event-capture.appcache 2014-06-03 09:51:54 +0000
+++ dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/event-capture.appcache 2014-06-12 23:12:59 +0000
@@ -85,7 +85,8 @@
../dhis-web-commons/javascripts/dhis2/dhis2.appcache.js
../dhis-web-commons/ouwt/ouwt.js
../dhis-web-commons/javascripts/dhis2/dhis2.translate.js
-../dhis-web-commons/javascripts/dhis2/dhis2.menu.js
+../dhis-web-commons/javascripts/dhis2/dhis.menu.js
+../dhis-web-commons/javascripts/dhis2/dhis.menu.ui.js
scripts/event-capture.js
scripts/app.js
=== modified file 'dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/i18n/en.json'
--- dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/i18n/en.json 2014-06-02 10:50:49 +0000
+++ dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/i18n/en.json 2014-06-12 23:12:59 +0000
@@ -71,14 +71,5 @@
"no": "NO",
"yes": "YES",
"offline_notification": "You are offline, data will be stored locally",
- "online_nofification": "You are online",
- "profile": "Profile",
- "applications": "Apps",
- "more_applications": "More apps",
- "search_apps": "Search apps",
- "settings": "Settings",
- "account": "Account",
- "help": "Help",
- "log_out": "Log out",
- "about_dhis2": "About DHIS 2"
+ "online_nofification": "You are online"
}
=== modified file 'dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/i18n/fr.json'
--- dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/i18n/fr.json 2014-05-24 08:58:21 +0000
+++ dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/i18n/fr.json 2014-06-12 23:12:59 +0000
@@ -68,14 +68,5 @@
"no": "NON",
"yes": "OUI",
"offline_notification": "Vous êtes actuellement hors connexion, vos données seront stockées localement",
- "online_nofification": "Vous êtes connecté",
- "profile": "Profil",
- "applications": "Apps",
- "more_applications": "Plus d'apps",
- "search_apps": "Recherche d'apps",
- "settings": "Paramètres",
- "account": "Compte",
- "help": "Aide",
- "log_out": "Déconnexion",
- "about_dhis2": "À propos de DHIS 2"
+ "online_nofification": "Vous êtes connecté"
}
\ No newline at end of file
=== modified file 'dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/index.html'
--- dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/index.html 2014-06-03 09:51:54 +0000
+++ dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/index.html 2014-06-12 23:12:59 +0000
@@ -64,6 +64,7 @@
<!-- Menu scripts -->
<script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.translate.js"></script>
<script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.menu.js"></script>
+ <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.menu.ui.js"></script>
<link type="text/css" rel="stylesheet" href="../dhis-web-commons/font-awesome/css/font-awesome.min.css"/>
<link type="text/css" rel="stylesheet" media="screen,print" href="../dhis-web-commons/css/light_blue/light_blue.css"/>
@@ -80,81 +81,8 @@
<img ng-click="home()" id="headerBanner" src="../dhis-web-commons/css/light_blue/logo_banner.png" style="cursor:pointer" title="{{'dhis2_home'| translate}}">
</div>
<div id="headerMessage" class="bold"></div>
-
- <!-- Menu html -->
- <ul id="menuLinkArea">
- <li id="profileDropDown_button">
- <a id="profileMenuLink" class="menu-link drop-down-menu-link">
- <i class="fa fa-user"></i>{{'profile'| translate}}
- </a>
- </li>
- <li id="appsDropDown_button">
- <a id="appsMenuLink" class="menu-link drop-down-menu-link">
- <i class="fa fa-th"></i>{{'applications'| translate}}
- </a>
- </li>
- </ul>
-
- <div id="appsDropDown" class="menuDropDownArea app-menu-dropdown appsMenuLink_menu" >
- <div class="caret-up-border"></div>
- <div class="caret-up-background"></div>
- <div class="menu-drop-down-wrap">
- <div class="menu-drop-down-scroll">
- <div class="apps-search-wrap">
- <input id="apps-search" class="apps-search" type="text" placeholder="{{'search_apps' | translate}}">
- <span id="apps-search-clear" class="fa fa-times-circle"></span>
- </div>
- <ul class="menuDropDownBox"><li class="menu-placeholder"><img src="../images/ajax-loader-bar.gif"></li></ul>
- </div>
- </div>
- <div class="apps-menu-bottom-button apps-menu-more"><a href="../dhis-web-commons-about/modules.action">{{'more_applications'| translate}}</a></div>
- <div class="apps-menu-bottom-button apps-scroll apps-scroll-up"><a class="fa fa-caret-up" href="#"></a></div>
- <div class="apps-menu-bottom-button apps-scroll apps-scroll-down"><a class="fa fa-caret-down" href="#"></a></div>
- </div>
-
- <div id="profileDropDown" class="menuDropDownArea app-menu-dropdown ui-helper-clearfix profileMenuLink_menu">
- <div class="caret-up-border"></div>
- <div class="caret-up-background"></div>
- <ul class="menuDropDownBox">
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-about/userSettings.action">
- <img src="../icons/usersettings.png" alt="{{'settings'| translate}}">
- <span>{{'settings'| translate}} </span>
- </a>
- </li>
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-about/showUpdateUserProfileForm.action">
- <img src="../icons/function-profile.png" alt="{{'profile'| translate}}">
- <span>{{'settings'| translate}} </span>
- </a>
- </li>
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-about/showUpdateUserAccountForm.action">
- <img src="../icons/function-account.png" alt="{{'account' | translate}}">
- <span>{{'account' | translate}} </span>
- </a>
- </li>
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-about/help.action">
- <img src="../icons/function-help-center.png" alt="{{'help' | translate}}">
- <span>{{'help' | translate}} </span>
- </a>
- </li>
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-security/logout.action">
- <img src="../icons/function-log-out.png" alt="{{'log_out' | translate}}">
- <span>{{'log_out' | translate}} </span>
- </a>
- </li>
- <li>
- <a class="app-menu-item" href="../dhis-web-commons-about/about.action">
- <img src="../icons/function-about-dhis2.png" alt="{{'about_dhis2' | translate}}">
- <span>{{'about_dhis2' | translate}} </span>
- </a>
- </li>
- </ul>
- </div>
- <!-- /Menu html -->
+
+ <div d2-menu></div>
</div>
=== modified file 'dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/scripts/app.js'
--- dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/scripts/app.js 2014-04-02 09:43:14 +0000
+++ dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/scripts/app.js 2014-06-12 23:12:59 +0000
@@ -11,7 +11,8 @@
'eventCaptureServices',
'eventCaptureFilters',
'angularLocalStorage',
- 'pascalprecht.translate'])
+ 'pascalprecht.translate',
+ 'd2Menu'])
.value('DHIS2URL', '..')