Gantt - Modifying the Mouse-over information on a project - gantt-chart

Good Morning;
I am looking to modify a Gantt Chart so that the Title found on the left and currently showing on the project are the same but when you hove the mouse over it, it will show a different set of information. Would also like to know the best way to separate the weeks with a noticeable break line that runs the entire gantt chart. Here is the code:
Page:
#using Kendo.Mvc.UI
<p></p>
<h2>#ViewBag.Title</h2>
#(Html.Kendo().Gantt<cpr_web.Models.TaskViewModel, cpr_web.Models.DependencyViewModel>()
.Name("Gantt")
.Views(views =>
{
views.WeekView(w => w.DayHeaderTemplate("#=kendo.toString(start, 'dd' )#").SlotSize(40));
views.MonthView(m => m.WeekHeaderTemplate("#=kendo.toString(start,'d', end,'d')#").SlotSize(150));
//views.YearView();
})
.Columns(columns =>
{
columns.Bound("title").Editable(false).Sortable(true).Width(100);
//columns.Bound("start").Format("{0:MM-dd}").Sortable(true).Width(10);
columns.Bound("State").Editable(false).Sortable(true).Width(30);
columns.Bound("City").Editable(false).Sortable(true).Width(40);
//columns.Bound("PercentComplete").Sortable(true).Width(10).Title("Complete");
})
.Events(e => {
e.Edit("editingGantt");
e.DataBound("databoundGantt");
e.Remove("unsupported");
e.Change("unsupported");
e.Move("unsupported");
e.MoveEnd("unsupported");
e.MoveStart("unsupported");
e.Resize("unsupported");
e.ResizeEnd("unsupported");
e.ResizeStart("unsupported");
})
.Navigatable(false)
.Editable(e => e.Confirmation(false))
.Toolbar(t =>
{
t.Add().Name("Menu").Template("<a href='/BackendSchedule/Index'>Schedule Menu</a>");
})
.ListWidth("450")
.ShowWorkDays(false)
.ShowWorkHours(false)
.Snap(true)
.Height(2000)
.DataSource(ds => ds
.Read(read => read
.Action("Tasks", "BackendSchedule")
)
.Model(m =>
{
m.Id(f => f.TaskID);
m.ParentId(f => f.ParentID);
m.OrderId(f => f.OrderId);
m.Field(f => f.Title);
m.Field(f => f.Title1);
m.Field(f => f.Start);
m.Field(f => f.End);
m.Field(f => f.Expanded).DefaultValue(false);
})
)
//.DependenciesDataSource(ds => ds
// .Read(read => read
// .Action("Dependencies", "BackendSchedule")
// )
// .Model(m =>
// {
// m.Id(f => f.DependencyID);
// m.PredecessorId(f => f.PredecessorID);
// m.SuccessorId(f => f.SuccessorID);
// m.Type(f => f.Type);
// })
//)
.Resources(r =>
{
r.Field("resources");
r.DataColorField("Color");
r.Field("PercentComplete");
r.DataSource(ds => ds
.Custom()
.Schema(s => s
.Model(m => m.Id("Id"))
.Data("Message")
)
.Transport(t =>
{
t.Read("GanttResources", "BackendSchedule");
})
);
})
)
#(Html.Kendo().Window().Name("utilityWindow")
.Title("Edit Job")
.Iframe(true)
.Visible(false)
.Modal(true)
.Draggable(true)
.Width(500)
.Height(250)
.Events(evt => evt
.Close("closeWindow")
)
)
<script>
kendo.culture().calendar.firstDay = 1;
function closeWindow(e) {
$(this.element).empty();
}
function unsupported(e) {
// remove not supported/permitted in this app
e.preventDefault();
}
function editingGantt(e) {
var jobId = e.task.title.split(':')[0];
var win = $("#utilityWindow").data("kendoWindow");
win.refresh({ url: "/BackendSchedule/_Jobs?jobId=" + jobId + "&source=gantt" });
win.setOptions({
title: "Edit Jobs",
width: 1000,
height: 600,
});
win.center().open();
e.preventDefault();
}
function databoundGantt(e) {
var gantt = $("#Gantt").data("kendoGantt")
var data = gantt.dataSource.data();
$.each(data, function (i,row){
var taskElement = $("div[data-uid=\"" + data[i].uid + "\"]");
if (row.percentComplete == 0) {
taskElement.addClass("color-green");
} else {
taskElement.addClass("color-red");
}
//alert(row.percentComplete);
});
}
</script>
Controller:
#region Gantt
[Authorize(Roles = "Manager, Administrator, Responsible Party")]
public ActionResult Gantt()
{
ViewBag.Title = "Manage Schedule";
return View();
}
public JsonResult GanttResources()
{
List<MessageModel> resources = new List<MessageModel>();
MessageModel resource = new MessageModel();
resource.Id = "0";
resource.Message = "green";
resources.Add(resource);
resource = new MessageModel();
resource.Id = "1";
resource.Message = "red";
resources.Add(resource);
return Json(resources, JsonRequestBehavior.AllowGet);
}
[Authorize]
public JsonResult Tasks([DataSourceRequest] DataSourceRequest request)
{
Jobs jobs = new Jobs();
var tasks = jobs.GetTasks();
return Json(tasks.AsQueryable().ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
public JsonResult Dependencies([DataSourceRequest] DataSourceRequest request)
{
var dependencies = new List<DependencyViewModel> {
new DependencyViewModel { DependencyID = 100, PredecessorID = 0, SuccessorID = 0, Type = DependencyType.FinishStart }
};
return Json(dependencies.AsQueryable().ToDataSourceResult(request));
}
public ActionResult Resources()
{
return View();
}
And Core: (Note the information desired is found on the title1)
public List<TaskViewModel> GetTasks()
{
List<TaskViewModel> tasks = new List<TaskViewModel>();
Teams teamObject = new Teams();
IEnumerable<TeamModel> teams = teamObject.GetTeam();
int taskId = 0;
int parentId = 0;
bool teamChanged = true;
foreach (TeamModel team in teams)
{
teamChanged = true;
taskId++;
parentId = taskId;
TaskViewModel task = new TaskViewModel();
task.TaskID = taskId;
task.ParentID = null;
task.Title = team.Name + ": " + team.LeadName;
task.Expanded = true;
task.Summary = true;
task.Start = DateTime.Today.AddDays(-7);
task.End = task.Start.AddMonths(3);
tasks.Add(task);
foreach (JobModel job in getJobs().Where(j => j.TeamId == team.Id).OrderBy(j => j.PlanStartDate))
{
taskId++;
task = new TaskViewModel();
task.TaskID = taskId;
task.ParentID = parentId;
task.Title = job.Id /*+ ": " + job.ContactName + ": " + job.Phone + ": " + job.FullAddress + ": " + job.City + ": " + job.State*/;
task.Title1 = job.Id + ": <p>" + job.ContactName + ": </br>" + job.Phone + ": </br>" + job.City + ": </br>" + job.State;
task.City = job.City;
task.State = job.State;
task.Start = job.PlanStartDate;
task.End = job.PlanEndDate;
task.Expanded =true;
task.Summary = false;
if (job.IsComplete)
{
task.PercentComplete = 0.001M;
}
else
{
task.PercentComplete = 0;
}
tasks.Add(task);
}
}
return tasks;
}
public IEnumerable<ScheduleModel> GetSchedule()
{
foreach (JobModel job in getJobs())
{
yield return new ScheduleModel
{
JobId = job.Id,
Title = job.Company,
ContactName = job.ContactName,
Email = job.Email,
Phone = job.Phone,
Start = job.PlanStartDate,
End = job.PlanEndDate,
IsAllDay = true,
TeamName=job.Company,
TeamId=job.CompanyId,
TeamColour=job.TeamId,
};
}
}

Ok so it turned out to be really simple, I just added this and can add any item in the taskViewModel to make it show up
.Tooltip(t =>
t.Template("Contractor: #=task.ContactName #, Phone: #=task.Phone #"))

Related

Edit a JSON object

I retrieved a JSON object from a local database, I want to edit a value (invItems) and add a new value to it (filed[filed.invItems]), then upload it back to the database, but it does not seem to work (the JSON does not seem to change)
async function invPut(itemID, message) {
var filed = await frenzyDB.getKey(id + "_invcache");
console.log("Before: " + filed)
newInvItems = filed.invItems + 1;
filed.invItems = newInvItems;
filed[filed.invItems] = itemID;
console.log("After: " + filed);
await frenzyDB.addKey(id + "_invcache", filed)
}
Console Output:
Before: {"invItems":0}
After: {"invItems":0}
It shows no errors, but the JSON doesnt change. Am I doing something wrong? If so, what can I do to fix it?
Thanks for all your help!
Notes:
frenzyDB is just a javascript file that deals with a standard REPL.it Database
Code of frenzyDB:
const Database = require("#replit/database")
const db = new Database()
async function addKey(key, value) {
await db.set(key, value).then(() => {return;});
}
async function getKey(key) {
return await db.get(key).then(value => {return value;});
}
function listAllKeys() {
db.list().then(keys => {return keys;});
}
async function hasKey(key) {
var keys = await listAllKeys();
if (keys.includes(key)) {
return true;
} else {
return false;
}
}
async function removeKey(key) {
await db.delete(key).then(() => {return;});
}
module.exports = {
addKey,
getKey,
listAllKeys,
hasKey,
removeKey
};
Edit: Latest code:
async function invPut(itemID, message) {
await init(message.author.id);
var filed = await frenzyDB.getKey(message.author.id + "_invcache");
console.log(filed)
const result = {};
result.invItems = (filed['invItems'] + 1) || 1;
result.hasOwnProperty(filed.invItems) ? result[filed.invItems + 1] = itemID : result[filed.invItems] = itemID;
console.log(result);
frenzyDB.addKey(message.author.id + "_invcache", result)
message.reply("A **"+ itemIDs[itemID].name + "** was placed in your inventory");
return true;
}
EDIT 2: Latest Console Output:
{ '4': 3, invItems: 5 }
{ '5': 3, invItems: 6 }
Any help will be appreciated!
Thanks
Try this
// Demo Data
const itemID = 10;
var filed = { "invItems" : 0 };
// Real function
console.log("Before: " + JSON.stringify(filed));
const result = {};
result.invItems = (filed['invItems'] + 1) || 1;
result.hasOwnProperty(filed.invItems) ? result[filed.invItems + 1] = itemID : result[filed.invItems] = itemID;
console.log("After: " + JSON.stringify(result));
The result I get is
Before: {"invItems":0}
After: {"0":10,"invItems":1}
You would then of course use result to store the data away in the DB.
async function invPut(itemID, message) {
// Typo?
var filed = await frenzyDB.getKey(itemID + "_invcache");
console.log("Before: " + filed)
const result = {};
result.invItems = (filed['invItems'] + 1) || 1;
result.hasOwnProperty(filed.invItems) ? result[filed.invItems + 1] = itemID : result[filed.invItems] = itemID;
console.log("After: " + result);
// Typo?
await frenzyDB.addKey(itemID + "_invcache", result)
}
Answer Edit:
const result = { ...filed };
result.invItems = (filed['invItems'] + 1) || 1;
result.hasOwnProperty(filed.invItems) ? result[filed.invItems + 1] = itemID : result[filed.invItems] = itemID;
console.log(JSON.stringify(result));
maybe this will help you
const json = fs.readFileSync(`${__dirname}/data/data.json`, "utf-8");
const inputData = JSON.parse(json);
inputData.push({input: 'front'}) // creates new element for data.json
-------------------------------------------
array.push({front: 'front', back: 'back'});

How to maintain a valid order book in kraken exchange with node,js

How's it going?
I got the example order book code in python (https://support.kraken.com/hc/en-us/articles/360027677512-Example-order-book-code-Python-) and translate it to javascript to run in node. But the book is wrong, it doesn't remove all old prices level. I'm sending my code below. I'd like help to solve this issue.
const websocket = require('ws');
const ws = new websocket('wss://ws.kraken.com');
const api_book = {'bid':[], 'ask':[]};
const api_depth = 10;
const api_output_book = () => {
bid = api_book['bid'].sort((x, y) => parseFloat(y[0])-parseFloat(x[0]));
ask = api_book['ask'].sort((x, y) => parseFloat(x[0])-parseFloat(y[0]));
console.log ('Bid\t\t\t\t\tAsk');
for (let x=0;x<api_depth;x++) {
console.log(`${bid[x][0]} (${bid[x][1]})\t\t\t${ask[x][0]} (${ask[x][1]})`);
}
}
const api_update_book = (side, data) => {
data.forEach((e) => {
let index = api_book[side].findIndex(o => o[0] == e[0]);
if (parseFloat(e[1]) > 0){
if(index < 0){
api_book[side].push([e[0],e[1]]);
} else {
api_book[side][index] = [e[0],e[1]];
}
} else {
api_book[side].splice(index,1);
}
});
if(side=='bid'){
api_book['bid'].sort((x, y) => parseFloat(y[0])-parseFloat(x[0]));
} else if(side=='ask'){
api_book['ask'].sort((x, y) => parseFloat(x[0])-parseFloat(y[0]));
}
}
ws.on('open', open = () => {
ws.send('{"event":"subscribe", "subscription":{"name":"book", "depth":'+api_depth+'}, "pair":["XBT/USD"]}');
console.log('Kraken websocket connected!');
});
ws.on('message', incoming = (data) => {
try {
data = JSON.parse(data.toString('utf8'));
if (data[1]) {
if (data[1]['as']) {
api_update_book('ask', data[1]['as'])
api_update_book('bid', data[1]['bs'])
} else if (data[1]['a'] || data[1]['b']) {
if (data[1]['a']) {
api_update_book('ask', data[1]['a']);
}
if (data[1]['b']) {
api_update_book('bid', data[1]['b']);
}
}
api_output_book();
}
} catch (error) {
console.log(error);
}
});
So I have also been playing around with Kraken's order book and came up with this solution using Angular. I also added a few console logs into the mix so that you can take it and run it in the browser. Hope this helps!
// variables
private ws = new WebSocket('wss://ws.kraken.com')
public asks = [];
public bids = [];
// Web Socket open connection
this.ws.onopen = () => {
this.ws.send(JSON.stringify(this.message));
console.log('Trade WS with Kraken connected')
}
// Fires when new data is received from web socket
this.ws.onmessage = (event) => {
var data = JSON.parse(event.data);
if (!data.event) {
if (data[1]['as']) {
this.asks = data[1]['as'];
this.bids = data[1]['bs'];
console.log('Initialised Book');
console.log(this.asks, this.bids);
} else if (data[1]['a'] || data[1]['b']) {
if (data[1]['a']) {
this.update_book(this.asks, 'ask', data[1]['a']);
}
if (data[1]['b']) {
this.update_book(this.bids, 'bid', data[1]['b']);
}
}
}
}
// Updating Orderbook
update_book (arr, side, data) {
if (data.length > 1) { // If 2 sets of data are received then the first will be deleted and the second will be added
let index = arr.findIndex(o => o[0] == data[0][0]); // Get position of first data
arr.splice(index, 1); // Delete data
arr.push([ data[1][0], data[1][1] ]); // Insert new data
console.log('Delete and Insert');
} else {
let index = arr.findIndex(o => o[0] == data[0][0]);
console.error(index);
if (index > -1) { // If the index matches a price in the list then it is an update message
arr[index] = [data[0][0], data[0][1]]; // Update matching position in the book
console.log('Updated ' + index);
} else { // If the index is -1 then it is a new price that came in
arr.push([data[0][0], data[0][1]]); // Insert new price
this.sort_book(arr, side); // Sort the book with the new price
arr.splice(10, 1); // Delete the 11th entry
console.log('Insert Only');
}
}
this.sort_book(arr, side); // Sort the order book
}
// Sort Orderbook
sort_book (arr, side) {
if (side == 'bid') {
arr.sort((x, y) => parseFloat(y[0]) - parseFloat(x[0]));
} else if (side == 'ask') {
arr.sort((x, y) => parseFloat(x[0]) - parseFloat(y[0]));
}
}
I would also recommend just having a look at this resource:
How to maintain a valid orderbook

How to migrate SSE chat node express to node hapi

I was testing a SSE node express chat in localhost.It was working perfectly. I was including a chat_server in a demo with hapijs as modular server...and it complain about the express syntax. How can I migrate the code to the right syntax in hapijs?
I am trying to solve changing writeHead and write methods because it's complaing about and adding stream package after searching answers in internet.
/*
* Request handlers
*/
function handleGetChat(req, res) {
console.log('handleGetChat received.');
// res(chatStream).code(200).type('text/event-stream').header('Connection', 'keep-alive').header('Cache-Control','no-cache');
// chatStream.write('\n');
(function(clientId) {
clients[clientId] = res;
clientNames[clientId] = req.params.name;
console.log('name {$req.params.name}');
req.on("close", () => {
delete clients[clientId];
actUserName = "";
sendText(clientNames[clientId] + " disconnected!", false);
delete clientNames[clientId];
});
})(++clientId);
sendText(req.params.name + " connected!", false);
let allMates = "";
for (cliId in clientNames) {
allMates += `${clientNames[cliId]}`;
if (cliId < clientId) allMates += " ";
}
sendText(`logged in [${allMates}]`, false);
}
let sendText = (text, showUserName = true) => {
for (clientId in clients) {
allMates += `${clientNames[cliId]}`;
if (cliId < clientId) allMates += " ";
}
sendText(logged in [${allMates}], false);
}
let sendText = (text, showUserName = true) => {
for (clientId in clients) {
let data = "";
let date = new Date();
let timestamp = `[${date.getHours()}:${date.getMinutes()}]`;
if (showUserName) {
data = `data: ${timestamp} <${actUserName}> ${text}\n\n`;
} else {
data = `data: ${timestamp} ${text}\n\n`;
}
//chatStream.push('data: ' + "\n\n");
}
};
function handleWriteChat(req, res) {
actUserName = req.body.name;
sendText(req.body.text);
res.json({ success: true });
}
The commented lines in the code above are the lines with syntax error in hapi. I was already changing the originals write and writeHead with chatstream.

Issue with uploading files on azure blob storage

I am working with azure blob storage, i have done that with PHP language, now i want to upload files on azure blob storage with jquery, so i used one plugin for that, when i try to upload file on that it is giving me error in console
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at (Reason: CORS header
‘Access-Control-Allow-Origin’ missing).
I read about the CORS configuration, and i enable that configuration in Azure Blob Storage, here is my screenshot for that
Here is my jquery code
$(function () {
var ju = {
sasUrl: $('#txtSAS'),
list: $('#tbFileList tbody'),
btnUpload: $('#btnUpload'),
btnClear: $('#btnClear'),
btnAddFile: $('#btnAddFile'),
sasSearchName: 'sas',
btnLink: $('#btnLink'),
linkPopover: $('#linkPopover'),
init: function () {
this.root = location.href;
if (this.root.indexOf('?') > 0) {
this.root = this.root.substr(0, this.root.indexOf('?'));
this.root = this.root.replace(/#/g, '');
}
this.btnClear.hide();
var sas = this.queryString(this.sasSearchName);
if (sas) {
this.sasUrl.val(sas);
}
this.list.blobuploader(
{
url: ju.sasUrl.val(),
beforeSend: function (blob) {
},
progress: function (blob) {
ju.progress(blob.element.closest('tr'), blob.loaded, blob.size);
},
success: function (blob, data, status) {
var st = blob.speed(true);
var msg = 'total time: ' + ((st.end - st.start) / 1000).toFixed(2) + 'S<br/>'
+ 'max speed: ' + st.max + '<br/>'
+ 'min speed: ' + st.min + '<br/>'
+ 'average speed: ' + st.average;
ju.status(blob.element, msg);
var download = '<a target="_blank" role="button" class="btn btn-link" href="'
+ blob.blobUrl
+ '" >' + blob.name + '</a>';
ju.log(blob.element.closest('tr').find('td:first'), download);
},
error: function (blob, block, xhr, desc, err) {
var msg = $('<span></span>');
msg.append('upload ' + blob.name + ' error.');
var btn = $('<button type="button" id="btnUpload" class="btn btn-sm btn-primary pull-right" role="button">Retry</button>');
btn.click(function () {
ju.retry($(this).closest('tr'));
});
msg.append(btn)
ju.status(blob.element, msg, 'danger');
}
});
this.btnClear.click(function () {
ju.clear();
});
this.btnAddFile.find('input').on('change', function () {
ju.add();
});
this.btnUpload.click(function () {
ju.upload();
});
this.btnLink.popover({
html: true,
content: this.linkPopover,
container: 'body'
});
this.btnLink.on('shown.bs.popover', function () {
var panel = $('#linkPopover');
panel.find('#txtShareUrl').val(ju.getLongUrl());
panel.find('#ckShortUrl').click(function () {
if ($(this).is(':checked')) {
ju.generateShortUrl();
} else {
panel.find('#txtShareUrl').val(ju.getLongUrl());
}
})
panel.find('.close').click(function () {
ju.btnLink.popover('toggle');
});
panel.find('#ckShortUrl').attr('checked', false);
panel.find('.loading').hide();
});
this.sasUrl.on('change', function () {
ju.linkPopover.find('#ckShortUrl').attr('ckecked', false);
ju.linkPopover.find('.loading').hide();
});
var code = $('.prettyprint');
code.text(code.text().replace('site-domain', location.origin));
},
progress: function (tr, loaded, total) {
var percent = (loaded / total * 100).toFixed(2);
var span = tr.find('td:last .percent');
if (span.length == 0) {
span = $('<span class="percent"/>').appendTo(tr.find('td:last').empty());
}
span.text(percent + '%');
},
log: function (td, message, type) {
var div = td.empty();
if (type) {
div = $('<div class="alert alert-' + type + '"/>').appendTo(td);
}
if (message instanceof jQuery) {
div.append(message);
} else {
div.html(message);
}
},
information: function (element, info, type) {
var td = element.closest('tr').find('td:eq(1)');
if (info) {
ju.log(td, info, type);
} else {
return td.html();
}
},
status: function (element, message, type) {
var td = element.closest('tr').find('td:last');
if (message) {
ju.log(td, message, type);
} else {
return td.html();
}
},
add: function () {
var tr = $('<tr/>'), td = $('<td/>');
var file = this.btnAddFile.find('input');
this.btnAddFile.append(file.clone(true));
var f = file.get(0).files[0];
td.append(file)
.append(f.name)
.appendTo(tr);
td = $('<td/>')
.append(f.type, f.type ? '<br/>' : '', (f.size / 1000).toFixed(2) + 'KB')
.appendTo(tr);
$('<td><span class="percent"></span></td>').appendTo(tr);
tr.appendTo(this.list);
this.btnClear.show();
},
setProperties: function () {
if (!this.sasUrl.val()) {
alert('Please typedin the Container SAS');
return;
}
var blockSize = parseInt($('#txtBlockSize').val());
var maxThread = parseInt($('#txtMaxThread').val());
if (isNaN(blockSize) || isNaN(maxThread)) {
alert("Block Size and Max Thread can only be number.");
return;
}
if (blockSize > 4096) {
alert('The block size should be less than 4096kb');
return;
}
if (blockSize < 1) {
alert('The block size should be greater than 1kb');
return;
}
if (maxThread < 0) {
maxThread = 0;
}
this.list.blobuploader('option', { maxThread: maxThread, blockSizeKB: blockSize, url: this.sasUrl.val() });
return true;
},
upload: function () {
if (this.setProperties()) {
this.list.blobuploader('upload');
}
},
retry: function (tr) {
if (this.setProperties()) {
if (tr) {
var element = tr.find('input[type="file"]');
var blob = this.list.blobuploader('blob', element);
this.list.blobuploader('retry', blob);
} else {
this.list.blobuploader('retry');
}
}
},
clear: function () {
this.list.empty();
this.btnClear.hide();
},
queryString: function (name, value) {
if (!value) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results == null ? "" : atob(decodeURIComponent(results[1].replace(/\+/g, " ")));
} else {
return name + '=' + encodeURIComponent(btoa(value));
}
},
getLongUrl: function () {
return this.root + '?' + this.queryString('sas', this.sasUrl.val());
},
generateShortUrl: function () {
var request = gapi.client.urlshortener.url.insert({
'resource': {
'longUrl': this.getLongUrl()
}
});
request.execute(function (response) {
if (response.id != null) {
ju.linkPopover.find('.loading').hide();
ju.linkPopover.find('#txtShareUrl').val(response.id);
}
else {
ju.linkPopover.find('.loading').text('error.');
}
});
}
}
ju.init();
prettyPrint();
})
function gapiload() {
gapi.client.setApiKey('AIzaSyDzeVB4WDi6azVvIu6uc8hIhWxf99dB6c8');
gapi.client.load('urlshortener', 'v1', function () { });
}
In the input we need to add "Input Your Container SAS Here" i am adding there
https://*****.blob.core.windows.net/?sv=2017-04-17&ss=bfqt&s‌​rt=sco&sp=rwdlacup&s‌​e=2017-09-10T01:51:2‌​0Z&st=2017-09-09T17:‌​51:20Z&spr=https&sig‌​=****** this SAS url, it will get this SAS url and after then we need to select file and upload it.
Can anyone please tell me what is exact issue ?
Thanks
I also download and test the library, it worked fine with following setting on my blob storage service. The MaxAgeInSeconds setting will cache the preflight OPTIONS request. I suggest you reset it to 0 and run your code again(Please use different browsers to test it).
In addition, there are multi CORS setting under Azure Storage panel. Please mark sure that you were setting the right one for Azure Blob Storage.

Opencart adding 3rd level category in filter module

i'm using a module for product filter,
In my admin backend i can able to set filter only for first and second level categories. I need to add 3rd level category too.
Below mentioned is my module controller file,
<?php
class ControllerModuleSuperCategoryMenu extends Controller {
private $error = array();
public function index() {
$this->data['current_version']='2.0.7';
//remove cache files
$this->cache->delete('product_filters');
$this->cache->delete('attribute_filters');
$this->load->language('module/supercategorymenu');
$this->document->setTitle($this->language->get('heading_title'));
$this->load->model('setting/setting');
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
$this->model_setting_setting->editSetting('supercategorymenu', $this->request->post);
$this->session->data['success'] = $this->language->get('text_success');
$this->redirect($this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL'));
}
$this->data['heading_title'] = $this->language->get('heading_title');
$this->data['tab_general'] = $this->language->get('tab_general');
$this->data['tab_settings'] = $this->language->get('tab_settings');
$this->data['tab_layouts'] = $this->language->get('tab_layouts');
$this->data['tab_contact'] = $this->language->get('tab_contact');
$this->data['entry_all_values'] = $this->language->get('entry_all_values');
$this->data['entry_list_number'] = $this->language->get('entry_list_number');
$this->data['entry_list_number_explanation'] = $this->language->get('entry_list_number_explanation');
$this->data['entry_pricerange'] = $this->language->get('entry_pricerange');
$this->data['entry_pricerange_explanation'] = $this->language->get('entry_pricerange_explanation');
$this->data['entry_set_vat'] = $this->language->get('entry_set_vat');
$this->data['entry_set_vat_explanation'] = $this->language->get('entry_set_vat_explanation');
$this->data['default_vat_price_range'] = $this->language->get('default_vat_price_range');
$this->data['default_vat_price_range_explanation'] = $this->language->get('default_vat_price_range_explanation');
$this->data['entry_manufacturer'] = $this->language->get('entry_manufacturer');
$this->data['entry_manufacturer_explanation'] = $this->language->get('entry_manufacturer_explanation');
$this->data['text_yes'] = $this->language->get('text_yes');
$this->data['text_no'] = $this->language->get('text_no');
$this->data['entry_count'] = $this->language->get('entry_count');
$this->data['entry_count_explanation'] = $this->language->get('entry_count_explanation');
$this->data['entry_ocscroll'] = $this->language->get('entry_ocscroll');
$this->data['entry_ocscroll_explanation'] = $this->language->get('entry_ocscroll_explanation');
$this->data['entry_nofollow'] = $this->language->get('entry_nofollow');
$this->data['entry_nofollow_explanation'] = $this->language->get('entry_nofollow_explanation');
$this->data['entry_track_google'] = $this->language->get('entry_track_google');
$this->data['entry_track_google_explanation'] = $this->language->get('entry_track_google_explanation');
$this->data['entry_ajax'] = $this->language->get('entry_ajax');
$this->data['entry_ajax_explanation'] = $this->language->get('entry_ajax_explanation');
$this->data['entry_order'] = $this->language->get('entry_order');
$this->data['entry_order_explanation'] = $this->language->get('entry_order_explanation');
$this->data['text_enabled'] = $this->language->get('text_enabled');
$this->data['text_disabled'] = $this->language->get('text_disabled');
$this->data['text_content_top'] = $this->language->get('text_content_top');
$this->data['text_content_bottom'] = $this->language->get('text_content_bottom');
$this->data['text_column_left'] = $this->language->get('text_column_left');
$this->data['text_column_right'] = $this->language->get('text_column_right');
$this->data['entry_layout'] = $this->language->get('entry_layout');
$this->data['entry_position'] = $this->language->get('entry_position');
$this->data['entry_status'] = $this->language->get('entry_status');
$this->data['entry_sort_order'] = $this->language->get('entry_sort_order');
$this->data['entry_value'] = $this->language->get('entry_value');
$this->data['entry_separator'] = $this->language->get('entry_separator');
$this->data['entry_examples'] = $this->language->get('entry_examples');
$this->data['entry_separator_explanation'] = $this->language->get('entry_separator_explanation');
$this->data['entry_values_explanation'] = $this->language->get('entry_values_explanation');
$this->data['text_none'] = $this->language->get('text_none');
$this->data['button_save'] = $this->language->get('button_save');
$this->data['button_cancel'] = $this->language->get('button_cancel');
$this->data['button_add_module'] = $this->language->get('button_add_module');
$this->data['button_remove'] = $this->language->get('button_remove');
if (isset($this->error['warning'])) {
$this->data['error_warning'] = $this->error['warning'];
} else {
$this->data['error_warning'] = '';
}
$this->data['breadcrumbs'] = array();
$this->data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/home', 'token=' . $this->session->data['token'], 'SSL'),
'separator' => false
);
$this->data['breadcrumbs'][] = array(
'text' => $this->language->get('text_module'),
'href' => $this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL'),
'separator' => ' :: '
);
$this->data['breadcrumbs'][] = array(
'text' => $this->language->get('heading_title'),
'href' => $this->url->link('module/supercategorymenu', 'token=' . $this->session->data['token'], 'SSL'),
'separator' => ' :: '
);
$this->data['action'] = $this->url->link('module/supercategorymenu', 'token=' . $this->session->data['token'], 'SSL');
$this->data['cancel'] = $this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL');
$this->data['settings'] = $this->url->link('module/supercategorymenu/settings', 'token=' . $this->session->data['token'], 'SSL');
$this->data['modules'] = array();
if (isset($this->request->post['supercategorymenu_module'])) {
$this->data['modules'] = $this->request->post['supercategorymenu_module'];
} elseif ($this->config->get('supercategorymenu_module')) {
$this->data['modules'] = $this->config->get('supercategorymenu_module');
}
$this->data['settings'] = array();
if (isset($this->request->post['supercategorymenu_settings'])) {
$this->data['settings'] = $this->request->post['supercategorymenu_settings'];
} elseif ($this->config->get('supercategorymenu_settings')) {
$this->data['settings'] = $this->config->get('supercategorymenu_settings');
}
if (isset($this->data['settings']['track_google'])){
$this->data['settings_trackgoogle']=$this->data['settings']['track_google'];
}else{
$this->data['settings_trackgoogle']=0;
}
if (isset($this->data['settings']['list_number'])){
$this->data['settings_listnumber']=$this->data['settings']['list_number'];
}else{
$this->data['settings_listnumber']=7;
}
if (isset($this->data['settings']['nofollow'])){
$this->data['settings_nofollow']=$this->data['settings']['nofollow'];
}else{
$this->data['settings_nofollow']=1;
}
if (isset($this->data['settings']['ajax'])){
$this->data['settings_ajax']=$this->data['settings']['ajax'];
}else{
$this->data['settings_ajax']=0;
}
if (isset($this->data['settings']['order'])){
$this->data['settings_order']=$this->data['settings']['order'];
}else{
$this->data['settings_order']="OH";
}
if (isset($this->data['settings']['ocscroll'])){
$this->data['settings_ocscroll']=$this->data['settings']['ocscroll'];
}else{
$this->data['settings_ocscroll']=0;
}
if (isset($this->data['settings']['countp'])){
$this->data['settings_countp']=$this->data['settings']['countp'];
}else{
$this->data['settings_countp']=1;
}
if (isset($this->data['settings']['pricerange'])){
$this->data['settings_pricerange']=$this->data['settings']['pricerange'];
}else{
$this->data['settings_pricerange']=1;
}
if (isset($this->data['settings']['setvat'])){
$this->data['settings_setvat']=$this->data['settings']['setvat'];
}else{
$this->data['settings_setvat']=1;
}
if (isset($this->data['settings']['manufacturer'])){
$this->data['settings_manufacturer']=$this->data['settings']['manufacturer'];
}else{
$this->data['settings_manufacturer']=1;
}
if (isset($this->data['settings']['tax_class_id'])){
$this->data['tax_class_id']=$this->data['settings']['tax_class_id'];
}else{
$this->data['tax_class_id']="";
}
$this->load->model('localisation/tax_class');
$this->data['tax_classes'] = $this->model_localisation_tax_class->getTaxClasses();
$this->load->model('module/supercategorymenu');
$this->data['categories'] = array();
$categories = $this->model_module_supercategorymenu->getCategories(0);
foreach ($categories as $category) {
if (isset($this->request->post['VALORES_'.$category['category_id'].''])) {
$this->data['category_attributes'][$category['category_id']]= $this->request->post['VALORES_'.$category['category_id'].''];
} else {
$this->data['category_attributes'][$category['category_id']] = $this->config->get('VALORES_'.$category['category_id'].'');
}
$children_data = array();
$children = $this->model_module_supercategorymenu->getCategories($category['category_id']);
foreach ($children as $child) {
if (isset($this->request->post['VALORES_'.$child['category_id'].''])) {
$this->data['category_attributes'][$child['category_id']]= $this->request->post['VALORES_'.$child['category_id'].''];
} else {
$this->data['category_attributes'][$child['category_id']] = $this->config->get('VALORES_'.$child['category_id'].'');
}
$results = $this->model_module_supercategorymenu->getCategoryAttributes($child['category_id']);
$attribute_data = array();
foreach ($results as $result) {
if (isset($this->data['category_attributes'][$child['category_id']]['attributes'][$result['attribute_id']])){
$attribute_checked=true;
$attribute_seperator=$this->data['category_attributes'][$child['category_id']]['attributes'][$result['attribute_id']]['separator'];
}else{
$attribute_checked=false;
$attribute_seperator="no";
}
$attribute_values=array();
$attribute_values = $this->model_module_supercategorymenu->getAttributeValues($result['attribute_id']);
//foreach ($res as $attribute_value){
//$attribute_values[key($res)]=$attribute_value;
//}
$attribute_data[] = array(
'attribute_id' => $result['attribute_id'],
'name' => $result['name'],
'checked' => $attribute_checked,
'separator' => $attribute_seperator,
'attribute_values'=> $attribute_values
);
}
$children_data[] = array(
'category_id' => $child['category_id'],
'name' => $child['name'],
'attributes' => $attribute_data
);
}
$results = $this->model_module_supercategorymenu->getCategoryAttributes($category['category_id']);
$attribute_data = array();
foreach ($results as $result) {
if (isset($this->data['category_attributes'][$category['category_id']]['attributes'][$result['attribute_id']])){
$attribute_checked=true;
$attribute_seperator=$this->data['category_attributes'][$category['category_id']]['attributes'][$result['attribute_id']]['separator'];
}else{
$attribute_checked=false;
$attribute_seperator="no";
}
$attribute_values_child=array();
$attribute_values_child = $this->model_module_supercategorymenu->getAttributeValues($result['attribute_id']);
//foreach ($res_child as $attribute_value_child){
//$attribute_values_child[key($res)]=$attribute_value_child;
//}
$attribute_data[] = array(
'attribute_id' => $result['attribute_id'],
'name' => $result['name'],
'checked' => $attribute_checked,
'separator' => $attribute_seperator,
'attribute_values'=> $attribute_values_child
);
}
$this->data['categories'][] = array(
'category_id' => $category['category_id'],
'name' => $category['name'],
'children' => $children_data,
'attributes' => $attribute_data,
//'valores_bd' => $this->data['category_attributes'][$category['category_id']]
);
}
$this->load->model('setting/extension');
if(in_array("ocscroll",$this->model_setting_extension->getInstalled('module'))){
$this->data['ocscroll']=true;
}else{
$this->data['ocscroll']=false;
}
$ch = curl_init();
// Now set some options (most are optional)
// Set URL to download
curl_setopt($ch, CURLOPT_URL,"http://opencart.tictachome.com/version/version.xml");
// Include header in result? (0 = yes, 1 = no)
curl_setopt($ch, CURLOPT_HEADER, 0);
// Should cURL return or print out the data? (true = return, false = print)
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Timeout in seconds
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
// Download the given URL, and return output
$output = curl_exec($ch);
// Close the cURL resource, and free system resources
curl_close($ch);
$analizador=simplexml_load_string($output,null);
$this->data['version']['version']=$analizador->children()->version;
$this->data['version']['whats_new']=$analizador->children()->whats_new;
foreach($analizador->children()->other_modules as $other_modules){
$this->data['version']['modules'][]=array(
'name' =>$other_modules->name,
'version' =>$other_modules->version,
'url' =>$other_modules->url,
'manual' =>$other_modules->manual,
'price' =>$other_modules->price,
'resume' =>$other_modules->resume,
);
}
$this->load->model('localisation/language');
$this->data['languages'] = $this->model_localisation_language->getLanguages();
$this->load->model('design/layout');
$this->data['layouts'] = $this->model_design_layout->getLayouts();
$this->template = 'module/supercategorymenu.tpl';
$this->children = array(
'common/header',
'common/footer'
);
$this->response->setOutput($this->render());
}
private function validate() {
if (!$this->user->hasPermission('modify', 'module/supercategorymenu')) {
$this->error['warning'] = $this->language->get('error_permission');
}
if (!$this->error) {
return true;
} else {
return false;
}
}
}
?>
Did anyone know how to add the 3rd level category too..
Please share your suggestions.
Thanks,

Resources