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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions www/core/components/sidemenu/controllers/iframe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// (C) Copyright 2015 Martin Dougiamas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

angular.module('mm.core.sidemenu')

/**
* Controller of the iframe viewer.
*
* @module mm.core.sidemenu
* @ngdoc controller
* @name mmSideMenuIframeViewCtrl
*/
.controller('mmSideMenuIframeViewCtrl', function($scope, $stateParams, $sce) {
$scope.title = $stateParams.title;
$scope.url = $sce.trustAsResourceUrl($stateParams.url);
});
31 changes: 17 additions & 14 deletions www/core/components/sidemenu/controllers/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ angular.module('mm.core.sidemenu')
$mmSideMenu.setScope($scope);
$scope.handlers = $mmSideMenuDelegate.getNavHandlers();
$scope.areNavHandlersLoaded = $mmSideMenuDelegate.areNavHandlersLoaded;
$scope.siteinfo = $mmSite.getInfo();
loadLogoutLabel();
loadSiteInfo();

$scope.logout = function() {
$mmSitesManager.logout().finally(function() {
Expand All @@ -40,25 +39,29 @@ angular.module('mm.core.sidemenu')
$scope.docsurl = docsurl;
});

function loadSiteInfo() {
var config = $mmSite.getStoredConfig();

$scope.siteinfo = $mmSite.getInfo();
$scope.logoutLabel = 'mm.sidemenu.' + (config && config.tool_mobile_forcelogout == "1" ? 'logout': 'changesite');

$mmSite.getDocsUrl().then(function(docsurl) {
$scope.docsurl = docsurl;
});

$mmSideMenu.getCustomMenuItems().then(function(items) {
$scope.customItems = items;
});
}

function updateSiteInfo() {
// We need to use $timeout to force a $digest and make $watch notice the variable change.
$scope.siteinfo = undefined;
$timeout(function() {
$scope.siteinfo = $mmSite.getInfo();
loadLogoutLabel();

// Update docs URL, maybe the Moodle release has changed.
$mmSite.getDocsUrl().then(function(docsurl) {
$scope.docsurl = docsurl;
});
loadSiteInfo();
});
}

function loadLogoutLabel() {
var config = $mmSite.getStoredConfig();
$scope.logoutLabel = 'mm.sidemenu.' + (config && config.tool_mobile_forcelogout == "1" ? 'logout': 'changesite');
}

var langObserver = $mmEvents.on(mmCoreEventLanguageChanged, updateSiteInfo);
var updateSiteObserver = $mmEvents.on(mmCoreEventSiteUpdated, function(siteid) {
if ($mmSite.getId() === siteid) {
Expand Down
14 changes: 14 additions & 0 deletions www/core/components/sidemenu/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ angular.module('mm.core.sidemenu', [])
$state.go('mm_login.init');
}
}
})

.state('site.iframe-view', {
url: '/iframe-view',
params: {
title: null,
url: null
},
views: {
'site': {
templateUrl: 'core/components/sidemenu/templates/iframe.html',
controller: 'mmSideMenuIframeViewCtrl'
}
}
});

})
Expand Down
92 changes: 91 additions & 1 deletion www/core/components/sidemenu/services/sidemenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,102 @@ angular.module('mm.core.sidemenu')
* @ngdoc service
* @name $mmSideMenu
*/
.factory('$mmSideMenu', function($log) {
.factory('$mmSideMenu', function($log, $mmLang, $mmSitesManager, mmCoreConfigConstants) {
$log = $log.getInstance('$mmSideMenu');

var self = {},
scope;

/**
* Get a list of custom menu items for a certain site.
*
* @module mm.core.sidemenu
* @ngdoc method
* @name $mmSideMenu#getCustomMenuItems
* @param {String} [siteId] Site ID. If not defined, current site.
* @return {Object[]} List of custom menu items.
*/
self.getCustomMenuItems = function(siteId) {
return $mmSitesManager.getSite(siteId).then(function(site) {
var itemsString = site.getStoredConfig('tool_mobile_custommenuitems'),
items,
position = 0, // Position of each item, to keep the same order as it's configured.
map = {},
result = [];

if (!itemsString || typeof itemsString != 'string') {
// Setting not valid.
return result;
}

// Add items to the map.
items = itemsString.split(/(?:\r\n|\r|\n)/);
angular.forEach(items, function(item) {
var values = item.split('|'),
id,
label = values[0] ? values[0].trim() : values[0],
url = values[1] ? values[1].trim() : values[1],
type = values[2] ? values[2].trim() : values[2],
lang = (values[3] ? values[3].trim() : values[3]) || 'none',
icon = values[4] ? values[4].trim() : values[4];

if (!label || !url || !type) {
// Invalid item, ignore it.
return;
}

id = url + '#' + type;
if (!icon) {
// Icon not defined, use default one.
icon = type == 'embedded' ? 'ion-qr-scanner' : 'ion-link';
}

if (!map[id]) {
// New entry, add it to the map.
map[id] = {
url: url,
type: type,
position: position,
labels: {}
};
position++;
}

map[id].labels[lang.toLowerCase()] = {
label: label,
icon: icon
};
});

if (!position) {
// No valid items found, stop.
return result;
}

return $mmLang.getCurrentLanguage().then(function(currentLang) {
var fallbackLang = mmCoreConfigConstants.default_lang || 'en';

// Get the right label for each entry and add it to the result.
angular.forEach(map, function(entry) {
var data = entry.labels[currentLang] || entry.labels.none || entry.labels[fallbackLang];
if (!data) {
// No valid label found, get the first one.
data = entry.labels[Object.keys(entry.labels)[0]];
}

result[entry.position] = {
url: entry.url,
type: entry.type,
label: data.label,
icon: data.icon
};
});

return result;
});
});
};

/**
* Hide the right side menu.
*
Expand Down
6 changes: 6 additions & 0 deletions www/core/components/sidemenu/templates/iframe.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<ion-view>
<ion-nav-title>{{ title }}</ion-nav-title>
<ion-content mm-state-class>
<mm-iframe src="url"></mm-iframe>
</ion-content>
</ion-view>
8 changes: 8 additions & 0 deletions www/core/components/sidemenu/templates/menu.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ <h2>{{siteinfo.fullname}}</h2>
<ion-spinner ng-if="loading" class="icon"></ion-spinner>
</a>
</li>
<li ng-repeat="item in customItems" class="mm-sidemenu-customitem">
<a ng-if="item.type != 'embedded'" menu-close class="item item-icon-left" ng-href="{{item.url}}" mm-link in-app="{{item.type == 'inappbrowser'}}" title="{{item.label}}">
<i class="icon {{item.icon}}"></i>{{item.label}}
</a>
<a ng-if="item.type == 'embedded'" menu-close class="item item-icon-left" ui-sref="site.iframe-view({title: item.label, url: item.url})" title="{{item.label}}">
<i class="icon {{item.icon}}"></i>{{item.label}}
</a>
</li>
<li>
<a menu-close class="item item-icon-left" ng-href="{{siteinfo.siteurl}}" mm-link auto-login="yes" title="{{ 'mm.sidemenu.website' | translate}}">
<i class="icon ion-earth"></i>{{ 'mm.sidemenu.website' | translate}}
Expand Down
29 changes: 26 additions & 3 deletions www/core/directives/iframe.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

angular.module('mm.core')

.constant('mmCoreIframeTimeout', 15000)

/**
* Directive to display content in an iframe.
*
Expand All @@ -27,7 +29,7 @@ angular.module('mm.core')
* @param {Mixed} [width=100%] Width of the iframe. If not defined, use 100%.
* @param {Mixed} [height=100%] Height of the iframe. If not defined, use 100%.
*/
.directive('mmIframe', function($log, $mmUtil, $mmText, $mmSite, $mmFS) {
.directive('mmIframe', function($log, $mmUtil, $mmText, $mmSite, $mmFS, $timeout, mmCoreIframeTimeout) {
$log = $log.getInstance('mmIframe');

var tags = ['iframe', 'frame', 'object', 'embed'];
Expand Down Expand Up @@ -195,17 +197,38 @@ angular.module('mm.core')

return {
restrict: 'E',
template: '<div class="iframe-wrapper"><iframe class="mm-iframe" ng-style="{\'width\': width, \'height\': height}" ng-src="{{src}}"></iframe></div>',
templateUrl: 'core/templates/iframe.html',
scope: {
src: '='
},
link: function(scope, element, attrs) {
var url = (scope.src && scope.src.toString()) || '', // Convert $sce URLs to string URLs.
iframe = angular.element(element.find('iframe')[0]);

scope.width = $mmUtil.formatPixelsSize(attrs.iframeWidth) || '100%';
scope.height = $mmUtil.formatPixelsSize(attrs.iframeHeight) || '100%';

var iframe = angular.element(element.find('iframe')[0]);
// Show loading only with external URLs.
scope.loading = !!url.match(/^https?:\/\//i);

treatFrame(iframe);

if (scope.loading) {
iframe.on('load', function() {
scope.loading = false;
$timeout(); // Use $timeout to force a digest and update the view.
});

iframe.on('error', function() {
scope.loading = false;
$mmUtil.showErrorModal('mm.core.errorloadingcontent', true);
$timeout(); // Use $timeout to force a digest and update the view.
});

$timeout(function() {
scope.loading = false;
}, mmCoreIframeTimeout);
}
}
};
});
33 changes: 26 additions & 7 deletions www/core/directives/link.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ angular.module('mm.core')
* @name mmLink
*
* @param {Boolean} [captureLink=false] If the link needs to be captured by the app.
* @param {Boolean} [inApp=false] True to open in embedded browser, false to open in system browser.
* @param {String} [autoLogin=check] If the link should be open with auto-login. Accepts the following values:
* "yes" -> Always auto-login.
* "no" -> Never auto-login.
Expand All @@ -33,9 +34,11 @@ angular.module('mm.core')
* Convenience function to correctly navigate, open file or url in the browser.
*
* @param {String} href HREF to be opened.
* @param {Mixed} [inApp] True to open in embedded browser, false to open in system browser.
* @param {String} [autoLogin=check] Whether to auto-login. "yes", "no" or "check".
*/
function navigate(href, autoLogin) {
function navigate(href, inApp, autoLogin) {
inApp = inApp && inApp !== 'false';
autoLogin = autoLogin || 'check';

if (href.indexOf('cdvfile://') === 0 || href.indexOf('file://') === 0) {
Expand All @@ -56,13 +59,29 @@ angular.module('mm.core')
// It's an external link, we will open with browser. Check if we need to auto-login.
if (!$mmSite.isLoggedIn()) {
// Not logged in, cannot auto-login.
$mmUtil.openInBrowser(href);
if (inApp) {
$mmUtil.openInApp(href);
} else {
$mmUtil.openInBrowser(href);
}
} else if (autoLogin == 'yes') {
$mmSite.openInBrowserWithAutoLogin(href);
if (inApp) {
$mmSite.openInAppWithAutoLogin(href);
} else {
$mmSite.openInBrowserWithAutoLogin(href);
}
} else if (autoLogin == 'no') {
$mmUtil.openInBrowser(href);
if (inApp) {
$mmUtil.openInApp(href);
} else {
$mmUtil.openInBrowser(href);
}
} else {
$mmSite.openInBrowserWithAutoLoginIfSameSite(href);
if (inApp) {
$mmSite.openInAppWithAutoLoginIfSameSite(href);
} else {
$mmSite.openInBrowserWithAutoLoginIfSameSite(href);
}
}
}
}
Expand All @@ -82,11 +101,11 @@ angular.module('mm.core')
if (attrs.captureLink && attrs.captureLink !== 'false') {
$mmContentLinksHelper.handleLink(href).then(function(treated) {
if (!treated) {
navigate(href, attrs.autoLogin);
navigate(href, attrs.inApp, attrs.autoLogin);
}
});
} else {
navigate(href, attrs.autoLogin);
navigate(href, attrs.inApp, attrs.autoLogin);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions www/core/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"errorfileexistssamename": "There's already a file with this name.",
"errorinvalidform": "The form contains invalid data. Please make sure to fill all required fields and that the data is valid.",
"errorinvalidresponse": "Invalid response received. Please contact your Moodle site administrator if the error persists.",
"errorloadingcontent": "Error loading content.",
"erroropenfilenoapp": "Error opening the file: no app found to open this kind of file.",
"erroropenfilenoextension": "Error opening the file: the file doesn't have extension.",
"erroropenpopup": "This activity is trying to open a popup. This is not supported in this app.",
Expand Down
4 changes: 4 additions & 0 deletions www/core/templates/iframe.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="iframe-wrapper" ng-class="{'mm-loading-container': loading}">
<iframe ng-show="!loading" class="mm-iframe" ng-style="{'width': width, 'height': height}" ng-src="{{src}}"></iframe>
<ion-spinner ng-if="loading"></ion-spinner>
</div>