summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFulup Ar Foll <fulup@iot.bzh>2016-01-27 13:01:16 +0100
committerFulup Ar Foll <fulup@iot.bzh>2016-01-27 13:01:16 +0100
commit712446796a33a47ea7e5fafd7950141ac8060530 (patch)
tree72ddf32d3dbf4207fe29a70f9c84819477ece38c
parent33940e952258bf1026a5f2c0687e4da01bc66004 (diff)
Handle Error Modal on upload
-rw-r--r--afm-client/app/Frontend/app.js1
-rw-r--r--afm-client/app/Frontend/etc/AppConfig.js5
-rw-r--r--afm-client/app/Frontend/etc/routes.js2
-rw-r--r--afm-client/app/Frontend/images/appli/isnotvalid.pngbin11124 -> 18859 bytes
-rw-r--r--afm-client/app/Frontend/images/appli/istoobig.pngbin35678 -> 18151 bytes
-rw-r--r--afm-client/app/Frontend/images/appli/w3c-widget.pngbin26269 -> 15525 bytes
-rw-r--r--afm-client/app/Frontend/pages/Home/Dashboard.html40
-rw-r--r--afm-client/app/Frontend/pages/Home/DashboardModule.js118
-rw-r--r--afm-client/app/Frontend/pages/Home/DashboardModule.scss71
-rw-r--r--afm-client/app/Frontend/pages/Sample/Sample.html35
-rw-r--r--afm-client/app/Frontend/pages/Sample/SampleModule.js18
-rw-r--r--afm-client/app/Frontend/pages/Sample/SampleModule.scss41
-rw-r--r--afm-client/app/Frontend/widgets/FormInput/UploadAppli.js121
13 files changed, 71 insertions, 381 deletions
diff --git a/afm-client/app/Frontend/app.js b/afm-client/app/Frontend/app.js
index eac36e4..1d8fc2e 100644
--- a/afm-client/app/Frontend/app.js
+++ b/afm-client/app/Frontend/app.js
@@ -17,7 +17,6 @@
'AppConfig',
'JQueryEmu',
'DashboardModule',
- 'SampleModule',
'UploadFiles',
'LinkButton',
'TokenRefresh',
diff --git a/afm-client/app/Frontend/etc/AppConfig.js b/afm-client/app/Frontend/etc/AppConfig.js
index 16a2c87..16c05b5 100644
--- a/afm-client/app/Frontend/etc/AppConfig.js
+++ b/afm-client/app/Frontend/etc/AppConfig.js
@@ -15,7 +15,8 @@
image : 'images/',
icons : 'images/icons/',
avatar: 'images/avatars/',
- audio : 'images/audio/'
+ audio : 'images/audio/',
+ appli : 'images/appli/'
},
myapi: { // Warning paths should end with /
@@ -43,7 +44,7 @@
.factory('AppCall', function ($http, AppConfig) {
var myCalls = {
get : function(plugin, action, query, callback) {
- query["token"] = AppConfig.session.token; // add token to provided query
+ query.token = AppConfig.session.token; // add token to provided query
$http.get('/api/' + plugin + '/' + action , {params: query}).then (callback, callback);
}
diff --git a/afm-client/app/Frontend/etc/routes.js b/afm-client/app/Frontend/etc/routes.js
index 18d281a..31b2d52 100644
--- a/afm-client/app/Frontend/etc/routes.js
+++ b/afm-client/app/Frontend/etc/routes.js
@@ -1 +1 @@
-var foundationRoutes = [{"name":"mysample","url":"/sample","controller":"SampleController as ctrl","animationIn":"slideInRight","path":"pages/Sample/Sample.html"},{"name":"Dashboard","url":"/dashboard","controller":"DashboardController as ctrl","animationIn":"slideInRight","path":"pages/Dashboard/Dashboard.html"},{"name":"dashboard","url":"/dashboard","controller":"DashboardController as ctrl","animationIn":"slideInRight","path":"pages/Home/Dashboard.html"}];
+var foundationRoutes = [{"name":"Dashboard","url":"/dashboard","controller":"DashboardController as ctrl","animationIn":"slideInRight","path":"pages/Dashboard/Dashboard.html"}];
diff --git a/afm-client/app/Frontend/images/appli/isnotvalid.png b/afm-client/app/Frontend/images/appli/isnotvalid.png
index 057c215..ae99e83 100644
--- a/afm-client/app/Frontend/images/appli/isnotvalid.png
+++ b/afm-client/app/Frontend/images/appli/isnotvalid.png
Binary files differ
diff --git a/afm-client/app/Frontend/images/appli/istoobig.png b/afm-client/app/Frontend/images/appli/istoobig.png
index 5614073..4e73423 100644
--- a/afm-client/app/Frontend/images/appli/istoobig.png
+++ b/afm-client/app/Frontend/images/appli/istoobig.png
Binary files differ
diff --git a/afm-client/app/Frontend/images/appli/w3c-widget.png b/afm-client/app/Frontend/images/appli/w3c-widget.png
index 74d3927..8a3beb9 100644
--- a/afm-client/app/Frontend/images/appli/w3c-widget.png
+++ b/afm-client/app/Frontend/images/appli/w3c-widget.png
Binary files differ
diff --git a/afm-client/app/Frontend/pages/Home/Dashboard.html b/afm-client/app/Frontend/pages/Home/Dashboard.html
deleted file mode 100644
index 036148a..0000000
--- a/afm-client/app/Frontend/pages/Home/Dashboard.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!-- Foundation Annotations generate tmp/route.js -->
----
-name: dashboard
-url: /dashboard
-controller: DashboardController as ctrl
-animationIn: slideInRight
----
-
-<h3>
-<img class="logo" src="images/logo/triskel_iot_bzhx250.png" alt="IoT.bzh Logo" style="height:150px;">
- Application Framework Manager Simple Client
-</h3>
-
-
-
-<div class="button-box box-content ">
- <appli-button ng-repeat="appliID in ctrl.appliIDs" store="ctrl.appliStore" handle={{appliID}} callback="ctrl.AppliCB"> </appli-button>
- <upload-appli class="ibz-right" label="Upload" icon="fi-upload" posturl="/api/post/upload-appli" callback="ctrl.FileUploaded" title="Upload AGL App"></upload-appli>
-</div>
-
-
-<div class="button-box box-content ">
-
- <submit-button class="session-button {{ctrl.APIcheck}}" icon="fi-play-circle" label="Start" clicked="ctrl.StartApp" ></submit-button>
- <submit-button class="session-button {{ctrl.APIrefresh}}" icon="fi-x-circle" label="Stop" clicked="ctrl.StopApp" ></submit-button>
- <submit-button class="session-button {{ctrl.APIreset}}" icon="fi-x" label="Remove" clicked="ctrl.RemoveApp" ></submit-button>
-
-</div>
-<div class="message-box box-content vertical grid-frame">
- <div class="response">
- <span class="grid-content noscroll req {{ctrl.status}} ">req= {{ctrl.request}}</span>
- <span class="grid-content noscroll res {{ctrl.status}} ">res= {{ctrl.response}}</span>
- <span class="grid-content noscroll status {{ctrl.status}}">status= {{ctrl.errcode}}</span>
- </div>
-</div>
-
-
-<link-button href="sample" icon="fi-home" label="sample"></link-button>
-<token-refresh autolog="true" callback="ctrl.AutoStart"></token-refresh>
-
diff --git a/afm-client/app/Frontend/pages/Home/DashboardModule.js b/afm-client/app/Frontend/pages/Home/DashboardModule.js
deleted file mode 100644
index f843df1..0000000
--- a/afm-client/app/Frontend/pages/Home/DashboardModule.js
+++ /dev/null
@@ -1,118 +0,0 @@
-(function() {
-'use strict';
-
-// WARNING: make sure than app/frontend/services/AppConfig.js match your server
-
-// list all rependencies within the page + controler if needed
-angular.module('DashboardModule', ['SubmitButton', 'TokenRefresh', 'AppliButton'])
-
- .controller('DashboardController', function ($http, AppConfig, Notification) {
- var scope = this; // I hate JavaScript
- scope.uuid ="none";
- scope.token ="none";
- scope.session="none";
- scope.status ="err-no";
- scope.appliIDs =[]; // array to hold applications ID
- scope.appliStore={}; // array to hold applications json description
-
- scope.ProcessResponse= function(data, errcode, headers, config) {
- var apiname= 'API'+ data.request.api.replace('-','_');
- scope.status = "err-ok";
- scope.errcode= errcode;
- scope.request = data.request;
- scope.response = data.response;
-
- // if token was refresh let's update AppConfig
- if (data.request.token) AppConfig.session.token = data.request.token;
- if (data.request.uuid) AppConfig.session.uuid = data.request.uuid;
- if (data.request.timeout) AppConfig.session.timeout = data.request.timeout;
-
- // Make sure we clean everything when Open/Close is called
- if (apiname === "APIcreate" || apiname === "APIreset") {
- scope.APIreset ='';
- scope.APIcreate ='';
- scope.APIrefresh='';
- scope.APIcheck ='';
- }
- scope[apiname]="success";
-
- // If we have a new token let's update it
- if (data.request.token) scope.token=data.request.token;
-
- console.log ("OK: "+ JSON.stringify(data));
- };
-
- scope.ProcessError= function(data, errcode, headers, config) {
- var apiname= 'API'+data.request.api.replace('-','_');
- scope.status = "err-fx";
- scope.errcode = errcode;
- scope.request = data.request;
- scope.response = "";
- scope[apiname]="fail";
-
- console.log ("FX: "+ JSON.stringify(data));
- };
-
- scope.OpenSession = function() {
- console.log ("OpenSession");
- var handler = $http.get(AppConfig.session.create + '?token='+AppConfig.session.initial);
-
- handler.success(scope.ProcessResponse);
- handler.error(scope.ProcessError);
- };
-
- scope.CheckSession = function() {
- console.log ("CloseSession");
- var handler = $http.get(AppConfig.session.check + '?token='+AppConfig.session.token);
-
- handler.success(scope.ProcessResponse);
- handler.error(scope.ProcessError);
- };
-
- scope.RefreshSession = function() {
- console.log ("RefreshSession");
- var handler = $http.get(AppConfig.session.refresh + '?token='+AppConfig.session.token);
-
- handler.success(scope.ProcessResponse);
- handler.error(scope.ProcessError);
- };
-
- scope.ResetSession = function() {
- console.log ("ResetSession");
- var handler = $http.get(AppConfig.session.reset + '?token='+AppConfig.session.token);
-
- handler.success(scope.ProcessResponse);
- handler.error(scope.ProcessError);
- };
-
- scope.AppliCB = function (appliID) {
- console.log ("Application Clicked ID=[%s]", appliID);
-
- };
-
- scope.AutoStart = function () {
- console.log ("AutoStart requesting Apps list");
- var handler = $http.get('/api/afm-main/runnables' + '?token='+AppConfig.session.token);
- handler.success(function(result) {
-
- // Check this is a valid response from Binder
- if (result.request.jtype !== "AJB_reply" && result.request.api !== "runnables") {
- Notification.error ({message: "Invalid Respond to /opa/afm-main/runnable result="+result, delay: 5000});
- return;
- }
-
- // loop on runnable application to prepare for display
- var appliIDs=[];
- for (var idx=0; idx < result.response.length; idx ++) {
- appliIDs[idx] = result.response [idx].id;
- scope.appliStore [result.response [idx].id] = result.response [idx];
- }
- scope.appliIDs = appliIDs; // avoid partial update to limit UI refresh
-
- });
- };
-
- });
-
-console.log ("Dashboard Controller Loaded");
-})(); \ No newline at end of file
diff --git a/afm-client/app/Frontend/pages/Home/DashboardModule.scss b/afm-client/app/Frontend/pages/Home/DashboardModule.scss
deleted file mode 100644
index 8bf04a1..0000000
--- a/afm-client/app/Frontend/pages/Home/DashboardModule.scss
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 "IoT.bzh"
- * Author "Fulup Ar Foll"
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-@import "app/ibz-mixins";
-
-$COLOR_SUCCESS: green;
-$COLOR_FAIL: red;
-
-token-refresh {
- display: block;
- float: right;
- margin: .5rem 1rem 0 0;
-}
-
-.button-box {
- height : 4.5rem;
-
- .session-button {
- float: left;
- width: 5rem;
- };
-
- .response > span{
- display: block;
- margin: .3rem .5rem .3rem .5rem;
- }
-
- .fail {
- color:$COLOR_FAIL;
- border: 1px solid darken($COLOR_FAIL,10%);
- }
- .success {
- color:$COLOR_SUCCESS;
- border: 1px solid darken($COLOR_SUCCESS,10%);
- }
-
-};
-
-.message-box {
- height : auto;
- width: 100%;
- font-size: .75rem;
-
- .response {
- .err-no { color:grey; }
- .res.err-ok { color: blue; }
- .req.err-ok { color:blueviolet; }
- .status.err-ok { color:green; }
- .status.err-fx { color:red; }
- }
-
-
-};
-
-
-
diff --git a/afm-client/app/Frontend/pages/Sample/Sample.html b/afm-client/app/Frontend/pages/Sample/Sample.html
deleted file mode 100644
index 03a4558..0000000
--- a/afm-client/app/Frontend/pages/Sample/Sample.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!-- Foundation Annotations generate tmp/route.js -->
----
-name: mysample
-url: /sample
-controller: SampleController as ctrl
-animationIn: slideInRight
----
-
-<h1><img class="logo" src="images/logo/triskel_iot_bzhx250.png" alt="IoT.bzh Logo" style="height:150px;">
- Post File Upload
-</h1>
-
-<div class="sample-box box-content">
-
- <!-- Usage: upload-xxxxx
- name = [xxxxxx] is use a field label for xform input field. Should match with server side
- category = [avatar] should match to a valid directory of thumbnail within AppConfig.path
- thumbnail= [tux-bzh.png] a valid image within AppConfig.paths.[category]
- istoobig = [istoobig.png] used image from AppConfig.paths.[category] when file is oversized
- maxsize = [xxx] maximum size in KB [default max depend on upload-type]
- accept = [image] acceptable accept for upload
- -->
- <upload-image name="avatar" category="avatar" thumbnail="tux-visitor.png" maxsize="100"
- posturl="/api/post/upload-image" callback="ctrl.FileUploaded" accept="image" title="Change your Avatar">
- </upload-image>
-
- <!-- Warning: name=xxx should match with what server expect [used as xform input name -->
- <upload-audio name="music" posturl="/api/post/upload-music" callback="ctrl.FileUploaded" title="Upload your Music"></upload-audio>
-
- <!-- Warning: name=xxx should match with what server expect [used as xform input name -->
- <upload-appli name="appli" posturl="/api/post/upload-appli" callback="ctrl.FileUploaded" title="Upload AGL App"></upload-appli>
-
-</div>
-
-<link-button href="home" icon="fi-home" label="home"></link-button>
diff --git a/afm-client/app/Frontend/pages/Sample/SampleModule.js b/afm-client/app/Frontend/pages/Sample/SampleModule.js
deleted file mode 100644
index 8ae82ea..0000000
--- a/afm-client/app/Frontend/pages/Sample/SampleModule.js
+++ /dev/null
@@ -1,18 +0,0 @@
-(function() {
-'use strict';
-
-// list all rependencies within the page + controler if needed
-angular.module('SampleModule', ['SubmitButton','UploadFiles'])
-
- .controller('SampleController', function ($http) {
- var scope = this; // I hate JavaScript
-
- console.log ("sample Init");
-
- scope.FileUploaded = function (response) {
- console.log ("FileUploaded response=%s", JSON.stringify(response));
- };
- });
-
-console.log ("SampleControler Loaded");
-})(); \ No newline at end of file
diff --git a/afm-client/app/Frontend/pages/Sample/SampleModule.scss b/afm-client/app/Frontend/pages/Sample/SampleModule.scss
deleted file mode 100644
index 7654424..0000000
--- a/afm-client/app/Frontend/pages/Sample/SampleModule.scss
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 "IoT.bzh"
- * Author "Fulup Ar Foll"
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-@import "app/ibz-mixins";
-
-
-.sample-box {
- display: block;
- height : 4.5rem;
-
- .sample-button {
- float: right;
- width: 5rem;
- };
-
- .muted-on-on,.muted-off-off{
- background: blueviolet;
- };
-
- .muted-error{
- background: red;
- };
-};
-
-
-
diff --git a/afm-client/app/Frontend/widgets/FormInput/UploadAppli.js b/afm-client/app/Frontend/widgets/FormInput/UploadAppli.js
index c1b33ac..1ef7ce8 100644
--- a/afm-client/app/Frontend/widgets/FormInput/UploadAppli.js
+++ b/afm-client/app/Frontend/widgets/FormInput/UploadAppli.js
@@ -39,9 +39,15 @@ var tmplAppli = '<input type="file" name="{{name}}-input" onchange="angular.elem
var tmplModal = '<span class="modal-text">Upload Application <b>{{appname}}</b> ?</span>' +
'<div>'+
- '<img ng-src="{{appicon}}">' +
- '<submit-button icon="fi-x" label="Cancel" clicked="refused"></submit-button>'+
- '<submit-button icon="fi-like" label="Install" clicked="accepted"></submit-button> ' +
+ '<img ng-src="{{icon}}">' +
+ '<submit-button icon="fi-x" label="Cancel" clicked="abandon"></submit-button>'+
+ '<submit-button icon="fi-like" label="Install" clicked="success"></submit-button> ' +
+ '</div>';
+
+var tmplError = '<span class="modal-text">Invalid Application <b>{{appname}}</b> ?</span>' +
+ '<div>'+
+ '<img ng-src="{{icon}}">' +
+ '<submit-button icon="fi-x" label="Close" clicked="abandon"></submit-button>'+
'</div>';
@@ -90,36 +96,26 @@ function LoadFileSvc (scope, files, fileCB) {
for (var i = 0; i < files.length; i++) {
this.file = files[i];
- console.log ("filetype=%s",this.file.type );
// Unknow Type !!! if (!this.file.type.match(scope.mimetype)) continue;
console.log ("Selected file=" + this.file.name + " size="+ this.file.size/1024 + " Type="+ this.file.type);
+
+ this.basename= this.file.name.split('/').reverse()[0];
// File to upload is too big
- if (this.file.size > scope.maxsize*1024) {
- scope.thumbnail = scope.istoobig; // warning if image path is wrong nothing happen
- scope.$apply('thumbnail'); // we short-circuit Angular resync Image
- return;
- }
-
- // This is not an uploadable file
- if(isNaN(this.file.size)) {
- scope.thumbnail = scope.isnotvalid;
- scope.$apply('thumbnail');
- return;
- }
-
- this.basename= this.file.name.split('/').reverse()[0];
- //scope.imgElem[0].file = this.file;
+ if (isNaN(this.file.size) || this.file.size > scope.maxsize*1024) {
+ setTimeout (fileCB,100); // On error asynchronous callback without argument
+
+ } else {
- // If File is an image let display it now
- if (fileCB) {
+ // If File is readable let's read it
var reader = new FileReader();
reader.readAsArrayBuffer(this.file);
reader.onload = fileCB;
- }
- // if everything is OK let's add file to xform
- xform.append(scope.name, this.file, this.file.name);
+
+ // if everything is OK let's add file to xform
+ xform.append(scope.name, this.file, this.file.name);
+ }
}
}
@@ -146,9 +142,9 @@ angular.module('UploadFiles',['AppConfig', 'ModalNotification', 'RangeSlider'])
scope.UpLoadFile=function (files) {
var handle;
var appicon;
+ var template;
- var accepted = function() {
- console.log ("Modal Accepted");
+ var success = function() {
// This Looks OK let's Post Xform/File
handle.postfile(attrs.posturl + "?token=" + AppConfig.session.token);
@@ -156,44 +152,61 @@ angular.module('UploadFiles',['AppConfig', 'ModalNotification', 'RangeSlider'])
$timeout (function() {scope.modal.destroy();}, 1000);
};
- var refused = function() {
- console.log ("Modal Refused");
+ var abandon = function() {
scope.modal.deactivate();
$timeout (function() {scope.modal.destroy();}, 1000);
};
var readerCB = function (upload) {
-
- var zipapp = new JSZip (upload.target.result);
- var thumbnail = zipapp.file("icon_128.png");
-
- // Check is we have a thumbnail within loaded Zipfile
- if (!thumbnail) {
- console.log ("This is not a valid Application Framework APP");
- scope.thumbnail=AppConfig.paths[scope.category] + 'isnotvalid.png';
- scope.$apply('thumbnail'); // we short-circuit Angular resync Image
- } else {
- //scope.imgElem[0].src = window.URL.createObjectURL(new Blob([thumbnail.asArrayBuffer()], {type: "image"}));
- appicon = window.URL.createObjectURL(new Blob([thumbnail.asArrayBuffer()], {type: "image"}));
+
+ // File upload fail handle error
+ if (! upload) {
+ if (handle.file.size > scope.maxsize*1024) {
+ appicon = scope.istoobig;
+ template= tmplError;
+ }
- // reference http://foundation.zurb.com/apps/docs/#!/angular-modules
- var config = {
- animationIn: 'slideInFromTop',
- contentScope: {
- accepted: accepted,
- refused: refused,
- appicon: appicon,
- appname: handle.basename
- }, template: tmplModal
- };
- // Popup Modal to render application data
- scope.modal = new ModalFactory(config);
- scope.modal.activate ();
+ if (isNaN(handle.file.size)) {
+ appicon = scope.isnotvalid;
+ template= tmplError;
+ }
+
+ } else {
+
+ var zipapp = new JSZip (upload.target.result);
+ var thumbnail = zipapp.file("icon_128.png");
+
+ // Check is we have a thumbnail within loaded Zipfile
+ if (!thumbnail) {
+ console.log ("This is not a valid Application Framework APP");
+ appicon = scope.isnotvalid;
+ template= tmplError;
+
+ } else {
+ //scope.imgElem[0].src = window.URL.createObjectURL(new Blob([thumbnail.asArrayBuffer()], {type: "image"}));
+ appicon = window.URL.createObjectURL(new Blob([thumbnail.asArrayBuffer()], {type: "image"}));
+ template = tmplModal;
+ }
}
+
+ // reference http://foundation.zurb.com/apps/docs/#!/angular-modules
+ var config = {
+ animationIn: 'slideInFromTop',
+ contentScope: {
+ success : success,
+ abandon : abandon,
+ icon : appicon,
+ appname : handle.basename
+ }, template : template
+ };
+ // Popup Modal to render application data
+ scope.modal = new ModalFactory(config);
+ scope.modal.activate ();
};
// Load file within browser and if OK call readerCB
handle = new LoadFileSvc (scope, files, readerCB);
+ console.log (handle);
};
// Initiallize default values from attributes values
@@ -206,7 +219,7 @@ angular.module('UploadFiles',['AppConfig', 'ModalNotification', 'RangeSlider'])
scope.label = attrs.label || 'Upload';
if (attrs.thumbnail) scope.isnotvalid= AppConfig.paths[scope.category] + attrs.isnotvalid;
- else scope.isnotvalid=AppConfig.paths[scope.category] + 'isnotvalid.png';
+ else scope.isnotvalid=AppConfig.paths[scope.category] + 'w3c-widget.png';
if (attrs.istoobig) scope.istoobig= AppConfig.paths[scope.category] + attrs.istoobig;
else scope.istoobig=AppConfig.paths[scope.category] + 'istoobig.png';