Skip to content

Commit

Permalink
Added a loading indicator gif. (oppia#5029)
Browse files Browse the repository at this point in the history
* Added Loading Indicator for the images

* CLRF

* Added for the imageAndRegions too

* added the exception for the file

* linting errors

* excluded path

* made the changes

* different size of loading indicator

* made the changes

* linting errors

* updated according to the comments

* Added the change for the loadingIndicator

* added the constant

* made changes according to the comment.
  • Loading branch information
ishucr7 authored and vojtechjelinek committed Jun 10, 2018
1 parent 96d392b commit 4ba0870
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 39 deletions.
Binary file added assets/images/activity/loadingIndicator.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion assets/rich_text_components_definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ var richTextComponents = {
"frontend_id": "image",
"tooltip": "Insert image",
"icon_data_url": "/rich_text_components/Image/Image.png",
"preview_url_template": "/imagehandler/<[explorationId]>/<[filepath]>",
"preview_url_template": "/imagehandler/<[explorationId]>/<[filepath.name]>",
"is_complex": false,
"requires_fs": true,
"is_block_element": true,
Expand Down
1 change: 1 addition & 0 deletions core/templates/dev/head/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ oppia.constant(
// We use a slash because this character is forbidden in a state name.
oppia.constant('PLACEHOLDER_OUTCOME_DEST', '/');
oppia.constant('INTERACTION_DISPLAY_MODE_INLINE', 'inline');
oppia.constant('LOADING_INDICATOR_URL', '/activity/loadingIndicator.gif');
oppia.constant('OBJECT_EDITOR_URL_PREFIX', '/object_editor_template/');
// Feature still in development.
// NOTE TO DEVELOPERS: This should be synchronized with the value in feconf.
Expand Down
12 changes: 12 additions & 0 deletions core/templates/dev/head/css/oppia.css
Original file line number Diff line number Diff line change
Expand Up @@ -1580,6 +1580,18 @@ pre.oppia-pre-wrapped-text {
opacity: 0;
}

/* Styles for the loading indicator shown while image is loading */
.oppia-image-loading-indicator-container {
background-color: rgba(224,242,241,1);
}

/* Style to center an image */
.center-image-horizontally {
display: block;
margin-left: auto;
margin-right: auto;
}

/* Styles for the collections learner view */

.oppia-collection-player-tiles-container {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,30 +108,108 @@ oppia.factory('ExtractImageFilenamesFromStateService', [
};

/**
* Extracts the filenames from the filepath-value attribute of the
* Extracts the filepath object from the filepath-value attribute of the
* oppia-noninteractive-image tags in the strHtml(given string).
* @param {string} strHtml - The string from which the filenames of images
* should be extracted.
* @param {string} strHtml - The string from which the object of
* filepath should be extracted.
*/
var _extractFilepathValueFromOppiaNonInteractiveImageTag = function(
strHtml) {
var filenames = [];
var fileInfo = [];
var dummyElement = document.createElement('div');
dummyElement.innerHTML = (
HtmlEscaperService.escapedStrToUnescapedStr(strHtml));

var imageTagList = dummyElement.getElementsByTagName(
'oppia-noninteractive-image');
for (i = 0; i < imageTagList.length; i++) {
filenames.push(imageTagList[i].getAttribute('filepath-with-value'));
var filepathObject = JSON.parse(
imageTagList[i].getAttribute('filepath-with-value'));
// The images already there in Oppia have image filenames as the value
// for the attribute 'filepath-with-value'. In explorations the
// the attribute value is an object of the form --
// {
// name: filename,
// width: widthOfImage,
// height: heightOfImage
// }
// So, we create an object similar to it for the images which had
// filenames as the attribute's value with default dimensions of
// 500px x 200px
if (!filepathObject.width) {
var filename = filepathObject;
filepathObject = {
name: filename,
width: 500,
height: 200
};
}
fileInfo.push(filepathObject);
}
// The name in the array is stored as '"image.png"'. We need to remove
// the inverted commas. We remove the first and the last character from
// the string (name).
filenames = filenames.map(function(filename) {
return filename.slice(1, filename.length - 1);
return fileInfo;
};

/**
* Gets the filenames of the images from the html provided.
* @param {string} htmlStr - The string from which the filenames of the
* images should be extracted.
*/
var _getImageFilenamesFromFilepathValue = function(htmlStr) {
var fileInfos = (
_extractFilepathValueFromOppiaNonInteractiveImageTag(htmlStr));
return fileInfos.map(function(fileInfo) {
return fileInfo.name;
});
};

/**
* Gets the dimensions of the images from the html provided.
* @param {string} htmlStr - The string from which the dimensions of the
* images should be extracted.
*/
var _getImageDimensionsFromFilepathValue = function(htmlStr) {
var fileInfos = (
_extractFilepathValueFromOppiaNonInteractiveImageTag(htmlStr));
var fileDimensions = {};
fileInfos.forEach(function(fileInfo){
var filename = fileInfo.name;
fileDimensions[filename] = {
width: fileInfo.width,
height: fileInfo.height
};
});
return fileDimensions;
};

/**
* Gets the dimensions of the images from the state provided.
* @param {object} state - The state from which the dimensions of the
* images should be extracted.
*/
var _getImageDimensionsInState = function(state) {
var fileDimensions = {};
if (state.interaction.id === INTERACTION_TYPE_IMAGE_CLICK_INPUT) {
var filepathObject = (
state.interaction.customizationArgs.imageAndRegions.value.imagePath);
if (!filepathObject.width) {
var filename = filepathObject;
filepathObject = {
name: filename,
width: 500,
height: 200
};
}
fileDimensions[filepathObject.name] = {
width: filepathObject.width,
height: filepathObject.height
};
}
var allHtmlOfState = _getAllHtmlOfState(state);
allHtmlOfState.forEach(function(htmlStr) {
Object.assign(fileDimensions,
_getImageDimensionsFromFilepathValue(htmlStr));
});
return filenames;
return fileDimensions;
};

/**
Expand All @@ -145,22 +223,21 @@ oppia.factory('ExtractImageFilenamesFromStateService', [
// directly stored in the customizationArgs.imageAndRegion.value
// .imagePath
if (state.interaction.id === INTERACTION_TYPE_IMAGE_CLICK_INPUT) {
filenamesInState.push(
var filepathObject = (
state.interaction.customizationArgs.imageAndRegions.value.imagePath);
filenamesInState.push(!filepathObject.name ? filepathObject :
filepathObject.name);
}
allHtmlOfState = _getAllHtmlOfState(state);
allHtmlOfState.forEach(function(htmlStr) {
filenamesInState = filenamesInState.concat(
_extractFilepathValueFromOppiaNonInteractiveImageTag(htmlStr));
_getImageFilenamesFromFilepathValue(htmlStr));
});
return filenamesInState;
};

return {
getImageFilenamesInState: _getImageFilenamesInState,
getImageFilenamesInHints: function(state) {
var hintsHtml = _getHintsHtml(state);
return _extractFilepathValueFromOppiaNonInteractiveImageTag(hintsHtml);
}
getImageDimensionsInState: _getImageDimensionsInState
};
}]);
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ oppia.factory('ImagePreloaderService', [
var _filenamesOfImageToBeDownloaded = [];
var _filenamesOfImageFailedToDownload = [];
var _exploration = null;
var _imageDimensions = null;
var _hasImagePreloaderServiceStarted = false;
// imageLoadedCallback is an object of objects (identified by the filenames
// which are being downloaded at the time they are required by the
// directive).The object contains the resolve method of the promise
Expand All @@ -39,9 +41,24 @@ oppia.factory('ImagePreloaderService', [
var _init = function(exploration) {
_exploration = exploration;
_states = exploration.states;
_getDimensionsOfImages();
_hasImagePreloaderServiceStarted = true;
};

/**
* Gets the dimensions of the images in the exploration.
*/
var _getDimensionsOfImages = function() {
_imageDimensions = {};
var states = (_states.getStateNames()).map(function(stateName) {
return _states.getState(stateName);
});
states.forEach(function(state){
Object.assign(_imageDimensions,
ExtractImageFilenamesFromStateService.getImageDimensionsInState(
state));
});
};
/**
* Gets the Url for the image file.
* @param {string} filename - Filename of the image whose Url is to be
Expand Down Expand Up @@ -86,8 +103,8 @@ oppia.factory('ImagePreloaderService', [
/**
* Gets image files names in Bfs order from the state.
* @param {string} sourceStateName - The name of the starting state
* from which the filenames should
* be obtained.
* from which the filenames should
* be obtained.
*/
var _getImageFilenamesInBfsOrder = function(sourceStateName) {
var stateNamesInBfsOrder = (
Expand Down Expand Up @@ -219,6 +236,9 @@ oppia.factory('ImagePreloaderService', [
return {
init: _init,
kickOffImagePreloader: _kickOffImagePreloader,
getDimensionsOfImage: function(filename) {
return _imageDimensions[filename];
},
onStateChange: _onStateChange,
isInFailedDownload: _isInFailedDownload,
isLoadingImageFile: function(filename) {
Expand All @@ -244,6 +264,9 @@ oppia.factory('ImagePreloaderService', [
};
}
});
},
inExplorationPlayer: function() {
return _hasImagePreloaderServiceStarted;
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
oppia.directive('oppiaInteractiveImageClickInput', [
'$sce', 'HtmlEscaperService', 'ExplorationContextService',
'imageClickInputRulesService', 'UrlInterpolationService',
'EVENT_NEW_CARD_AVAILABLE', 'EDITOR_TAB_CONTEXT', 'ImagePreloaderService',
'ImagePreloaderService', 'EVENT_NEW_CARD_AVAILABLE', 'EDITOR_TAB_CONTEXT',
'LOADING_INDICATOR_URL',
function(
$sce, HtmlEscaperService, ExplorationContextService,
imageClickInputRulesService, UrlInterpolationService,
EVENT_NEW_CARD_AVAILABLE, EDITOR_TAB_CONTEXT, ImagePreloaderService) {
ImagePreloaderService, EVENT_NEW_CARD_AVAILABLE, EDITOR_TAB_CONTEXT,
LOADING_INDICATOR_URL) {
return {
restrict: 'E',
scope: {
Expand All @@ -45,9 +47,33 @@ oppia.directive('oppiaInteractiveImageClickInput', [
($attrs.highlightRegionsOnHoverWithValue === 'true');
$scope.filepath = imageAndRegions.imagePath;
$scope.imageUrl = '';

ImagePreloaderService.getImageUrl($scope.filepath)
$scope.loadingIndicatorUrl = UrlInterpolationService
.getStaticImageUrl(LOADING_INDICATOR_URL);
$scope.isLoadingIndicatorShown = false;
if (ImagePreloaderService.inExplorationPlayer()) {
$scope.isLoadingIndicatorShown = true;
$scope.dimensions = (
ImagePreloaderService.getDimensionsOfImage($scope.filepath.name));
// For aligning the gif to the center of it's container
var loadingIndicatorSize = 120;
if ($scope.dimensions.height < 124) {
loadingIndicatorSize = 24;
}
var paddingTop = Math.max(0, (($scope.dimensions.height * 0.5) -
(loadingIndicatorSize * 0.5)));
$scope.loadingIndicatorContainerStyle =
{
'padding-top': paddingTop + 'px',
height: $scope.dimensions.height + 'px'
};
$scope.loadingIndicatorStyle = {
height: loadingIndicatorSize + 'px',
width: loadingIndicatorSize + 'px'
};
}
ImagePreloaderService.getImageUrl($scope.filepath.name)
.then(function(objectUrl) {
$scope.isLoadingIndicatorShown = false;
$scope.imageUrl = objectUrl;
});
$scope.mouseX = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@

<div ng-if="!imageUrl" translate="I18N_INTERACTIONS_IMAGE_CLICK_SELECT"></div>

<div class="image-click-container" ng-if="imageUrl">
<div ng-if="isLoadingIndicatorShown" class="oppia-image-loading-indicator-container" ng-style="loadingIndicatorContainerStyle">
<img ng-src="<[loadingIndicatorUrl]>" class="center-image-horizontally" ng-style="loadingIndicatorStyle" alt="Loading...">
</div>

<div class="image-click-container" ng-if="!isLoadingIndicatorShown">
<img ng-src="<[imageUrl]>"
class="oppia-image-click-img"
ng-click="onClickImage($event)"
Expand Down
9 changes: 7 additions & 2 deletions extensions/objects/templates/FilepathEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ oppia.directive('filepathEditor', [
// (e.g. if this is part of an editable list).
$scope.$watch('value', function(newValue) {
if (newValue) {
$scope.setSavedImageFilename(newValue, false);
$scope.setSavedImageFilename(newValue.name, false);
}
});

Expand Down Expand Up @@ -583,6 +583,7 @@ oppia.directive('filepathEditor', [
};

$scope.setSavedImageFilename = function(filename, updateParent) {
var dimensions = $scope.calculateTargetImageDimensions();
$scope.data = {
mode: MODE_SAVED,
metadata: {
Expand All @@ -592,7 +593,11 @@ oppia.directive('filepathEditor', [
};
if (updateParent) {
AlertsService.clearWarnings();
$scope.value = filename;
$scope.value = {
name: filename,
width: dimensions.width,
height: dimensions.height
};
}
};

Expand Down
2 changes: 1 addition & 1 deletion extensions/objects/templates/ImageWithRegionsEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ oppia.directive('imageWithRegionsEditor', [
if (newVal !== '') {
// Loads the image in hanging <img> tag so as to get the
// width and height.
$('<img/>').attr('src', $scope.getPreviewUrl(newVal)).on(
$('<img/>').attr('src', $scope.getPreviewUrl(newVal.name)).on(
'load', function() {
$scope.originalImageWidth = this.width;
$scope.originalImageHeight = this.height;
Expand Down
4 changes: 2 additions & 2 deletions extensions/objects/templates/image_with_regions_editor.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
schema="{type: 'custom', obj_type: 'Filepath'}">
</schema-based-editor>
</div>
<div style="position: relative" ng-if="$parent.value.imagePath !== ''">
<div style="position: relative" ng-if="$parent.value.imagePath.name !== ''">
<div>Add new regions by clicking on the image and dragging:</div>
<svg class="oppia-image-with-regions-editor-svg"
width="100%"
Expand All @@ -12,7 +12,7 @@
ng-mousedown="onSvgMouseDown($event)"
ng-mousemove="onSvgMouseMove($event)"
ng-mouseup="onSvgMouseUp($event)">
<image ng-href="<[getPreviewUrl($parent.$parent.value.imagePath)]>"
<image ng-href="<[getPreviewUrl($parent.$parent.value.imagePath.name)]>"
xlink:href=""
x="0"
y="0"
Expand Down
Loading

0 comments on commit 4ba0870

Please sign in to comment.