I'm absolutely newbie in the Dojo, so my question may be too evident. Sorry.
I've programmatically created the complex menu, including MenuBar, based on the rows, selected from the DB.
All problems were solved besides one: the alignment of the final items and submenu items differ.How it looks like All submenus primarily were rendered in the same line. Only by adding the MenuSeparator I was able to divide them.
I'm lost I've found the example in the Internet, that shows exactly what I need (including the right-hand arrow for submenus) Example . I've used exactly the same algorithm to create menu. But I cannot get the same result.
Please, help.
I've noted that the image is not accessible.
In pure text it looks like:
Final 1
Final 2
Final 3
DropDown 1
DropDown 2
Indent depends on the submenu width.
Think, now I know what happened (don't know though, how to work around it).
The problem is the widget rendering.
The final menu option (leaf) is rendered as table row (tr and td tags).
The PopupMenuItem is rendered as div between rows.
Once more, I have no clue, how to avoid it.
Here is the code. A couple of notes:
1.The rows is the two dimensional array
2.The rows with ParentID=0 are the MenuBarItems
3.pM is the MenuBar widget
createMenu: function (rows, pM) {
var me = this; // for references from the event handlers, where 'this' means event origin (instead of lang.hitch)
// First define the indexes of the DB fields
var xMenu_Id;
var xMenu_Title;
var xParent;
var xURL;
var xUser_Roles;
var i;
for (i = 0; i < rows[0].length; i++) {
switch (rows[0][i]) {
case 'Menu_Id':
xMenu_Id = i;
break;
case 'Menu_Title':
xMenu_Title = i;
break;
case 'Parent':
xParent = i;
break;
case 'URL':
xURL = i;
break;
case 'User_Roles':
xUser_Roles = i;
break;
}
}
// Define the function to filter the menu rows
// Parameters: r - two-dimentional rows array
// p - criterion (the parent menu ID)
// idx - index of needed field
// f - returned filtered array (no need to use in calling statement)
var filterArray = function (r, p, idx, f) {
f = dojo.filter(r, function (item) {
return item[idx] == p;
});
return f;
}
// Define the recurcive function to create the sub menu tree for Menu bar item
// Parameters: parentMenu - the menu to add childs
// parentID - the ID of parent menu to select direct children
// role - current user role
var subMenuFactory = function (parentMenu, parentID, role) {
var i;
var fa = filterArray(rows, parentID, xParent);
var sub;
for (i = 0; i < fa.length; i++) {
if (fa[i][xUser_Roles].indexOf(role) >= 0 || fa[i][xUser_Roles] == 'all') {
if (fa[i][xURL] != '0') { // leaf
url = fa[i][xURL];
parentMenu.addChild(new MenuItem({
dir: 'ltr',
label: fa[i][xMenu_Title],
action: fa[i][xURL],
onClick: function () { me.menuAction(this.action); }
}));
}
else { // DropDown Node
sub = new DropDownMenu({ dir: 'ltr' });
subMenuFactory(sub, fa[i][xMenu_Id], role);
parentMenu.addChild(new MenuSeparator({}));
parentMenu.addChild(new PopupMenuBarItem({
dir: 'ltr',
label: fa[i][xMenu_Title],
popup: sub
}));
}
}
}
}
// Get array of Menu bar items
var filtered = filterArray(rows, 0, xParent);
var pSub;
var user_Role = this.user.Role;
for (i = 0; i < filtered.length; i++) {
if (filtered[i][xUser_Roles].indexOf(user_Role) >= 0 || filtered[i][xUser_Roles]=='all') {
if (filtered[i][xURL] != '0') // leaf
{
pM.addChild(new MenuBarItem({
dir: 'ltr',
label: filtered[i][xMenu_Title],
action: filtered[i][xURL],
onClick: function () { me.menuAction(this.action); }
}));
}
else { // DropDown Node
pSub = new DropDownMenu({ dir: 'ltr' });
subMenuFactory(pSub, filtered[i][xMenu_Id],user_Role);
pM.addChild(new PopupMenuBarItem({
dir: 'ltr',
label: filtered[i][xMenu_Title],
popup: pSub
}));
}
}
}
},
I've found what's the problem. In the required array of define I erroneously import PopupMenubarItem instead of PopupMenuItem. In the function the parameter is named right - PopupMenuItem, but evidently it couldn't help a lot...
Thanks to everyone who tried to help me.
Regards,
Gena
Related
Hi i am trying to add two new fields to the Barcode mobile view. I went through the default js code of odoo, but didn't find a way to add my custome fields to it.
Here is the default code
stock_barcode/static/src/js/client_action/lines_widget.js
init: function (parent, page, pageIndex, nbPages) {
this._super.apply(this, arguments);
this.page = page; #don't know where this argument page coming from in argument list.
this.pageIndex = pageIndex;
this.nbPages = nbPages;
this.mode = parent.mode;
this.groups = parent.groups;
this.model = parent.actionParams.model;
this.show_entire_packs = parent.show_entire_packs;
this.displayControlButtons = this.nbPages > 0 && parent._isControlButtonsEnabled();
this.displayOptionalButtons = parent._isOptionalButtonsEnabled();
this.isPickingRelated = parent._isPickingRelated();
this.isImmediatePicking = parent.isImmediatePicking ? true : false;
this.sourceLocations = parent.sourceLocations;
this.destinationLocations = parent.destinationLocations;
// detect if touchscreen (more complicated than one would expect due to browser differences...)
this.istouchSupported = 'ontouchend' in document ||
'ontouchstart' in document ||
'ontouchstart' in window ||
navigator.maxTouchPoints > 0 ||
navigator.msMaxTouchPoints > 0;
},
In _renderLines function,
_renderLines: function () {
//Skipped some codes here
// Render and append the lines, if any.
var $body = this.$el.filter('.o_barcode_lines');
console.log('this model',this.model);
if (this.page.lines.length) {
var $lines = $(QWeb.render('stock_barcode_lines_template', {
lines: this.getProductLines(this.page.lines),
packageLines: this.getPackageLines(this.page.lines),
model: this.model,
groups: this.groups,
isPickingRelated: this.isPickingRelated,
istouchSupported: this.istouchSupported,
}));
$body.prepend($lines);
for (const line of $lines) {
if (line.dataset) {
this._updateIncrementButtons($(line));
}
}
$lines.on('click', '.o_edit', this._onClickEditLine.bind(this));
$lines.on('click', '.o_package_content', this._onClickTruckLine.bind(this));
}
In the above code, you can see this.page.lines field, i need to add my custom two more fields.
Actually it's dead-end for me.
Any solution?
I really need some idea on this. Basically, i'm working to sort list by click a button. If i click up button, the list will go up which the index of selected list will reduced by one. And when i click down button, the list will go down which the index of selected list will increased by one. I used the approach to remove the selected list for a temporary, then insert the list to the different index according to user. i have settled the remove part but i have no idea on insert part. Please help.
These are the code to remove selected list.
var removeSelectedItems = Ext.getCmp('SearchRefSlipMain_List').getSelection()[0]; Ext.getCmp('SearchRefSlipMain_List').getStore().remove(removeSelectedItems);
What left is only to insert the row of list that i have been removed to another row (different index) according to user.
the button:
{
xtype: 'button',
iconCls: 'arrow_down',
handler: function () {
RowDown();
}
}
This is the function:
function RowDown(){
var direction = 1 // 1 or -1
var record = Ext.getCmp('Settings_SetTreatmentList_TreatmentDetail_List').getSelection()[0]; //list id
if (!record) {
return;
}
var index = Ext.getCmp('Settings_SetTreatmentList_TreatmentDetail_List').getStore().indexOf(record);
if (direction < 0) {
index--;
if (index < 0) {
return;
}
} else {
index++;
if (index >= Ext.getCmp('Settings_SetTreatmentList_TreatmentDetail_List').getStore().getCount()) {
return;
}
}
Ext.getCmp('Settings_SetTreatmentList_TreatmentDetail_List').getStore().remove(record);
Ext.getCmp('Settings_SetTreatmentList_TreatmentDetail_List').getStore().insert(index, record);
}
***if move the selected list up, change the direction = -1
* https://www.sencha.com/forum/showthread.php?48472-how-to-move-the-grid-s-row-up-and-down (i got the solution from here, just change a bit according to Sencha Touch)
Usually you do not change the list, but the store that fills the list.
If this does not help, can you setup a fiddle here:
https://fiddle.sencha.com/#view/editor
(just save it and add the link to the fiddle in your question)
I changed your answer, which should have the same result, but way faster:
function RowDown() {
var direction = 1, // 1 or -1
treatmentDetail = Ext.getCmp('Settings_SetTreatmentList_TreatmentDetail_List'),
// or use reference
// treatmentDetail = this.lookup('Settings_SetTreatmentList_TreatmentDetail_List'),
record = treatmentDetail.getSelection()[0], //list id
store, index;
if (!record) {
return;
}
store = treatmentDetail.getStore(),
index = store.indexOf(record);
index = index + (1 * direction);
if (index >= store.getCount() || index < 0) {
return
}
store.remove(record);
store.insert(index, record);
}
Not sure why facebook refered me here but anyhow, let me ask the question. I have a group on facebook with over 4000 members. I want to delete old members that are not active on the group anymore. Is there a way to select multiple users for deletion?
How to get a list of ID's of your facebook group to avoid removal of active users, it's used to reduce as well a group from 10.000 to 5000 members as well as removal of not active members or old members "You will risk removing some few viewers of the group" "remember to open all comments while you browse down the page":
You will need to have Notepad++ for this process:
After you save the HTML. Remove all information before of document:
"div id=contentArea" to
"div id=bottomContent"
to avoid using messenger ID's,
somehow script will run problems if you have ID's by blocked users.
As well as a different example of how to parse as well as text and code out of HTML. And a range of numbers if they are with 2 digits up to 30.
You can try this to purge the list of member_id= and with them along with numbers from 2 to up to 30 digits long. Making sure only numbers and whole "member_id=12456" or "member_id=12" is written to file. Later you can replace out the member_id= with blanking it out. Then copy the whole list to a duplicate scanner or remove duplicates. And have all unique ID's. And then use it in the Java code below.
"This is used to purge all Facebook user ID's by a group out of a single HTML file after you saved it scrolling down the group"
Find: (member_id=\d{2,30})|.
Replace: $1
You should use the "Regular Expression" and ". matches newline" on above code.
Second use the Extended Mode on this mode:
Find: member_id=
Replace: \n
That will make new lines and with an easy way to remove all Fx0 in all lines to manually remove all the extra characters that come in buggy Notepad++
Then you can easily as well then remove all duplicates. Connect all lines into one single space between. The option was to use this tool which aligns the whole text with one space between each ID: https://www.tracemyip.org/tools/remove-duplicate-words-in-text/
As well then again "use Normal option in Notepad++":
Find: "ONE SPACE"
Replace ','
Remember to add ' to beginning and end
Then you can copy the whole line into your java edit and then remove all members who are not active. If you though use a whole scrolled down HTML of a page. ['21','234','124234'] <-- remember right characters from beginning. Extra secure would be to add your ID's to the beginning.
You put your code into this line:
var excludedFbIds = ['1234','11223344']; // make sure each id is a string!
The facebook group removal java code is on the user that as well posted to this solution.
var deleteAllGroupMembers = (function () {
var deleteAllGroupMembers = {};
// the facebook ids of the users that will not be removed.
// IMPORTANT: bobby.leopold.5,LukeBryannNuttTx!
var excludedFbIds = ['1234','11223344']; // make sure each id is a string!
var usersToDeleteQueue = [];
var scriptEnabled = false;
var processing = false;
deleteAllGroupMembers.start = function() {
scriptEnabled = true;
deleteAll();
};
deleteAllGroupMembers.stop = function() {
scriptEnabled = false;
};
function deleteAll() {
if (scriptEnabled) {
queueMembersToDelete();
processQueue();
}
}
function queueMembersToDelete() {
var adminActions = document.getElementsByClassName('adminActions');
console.log(excludedFbIds);
for(var i=0; i<adminActions.length; i++) {
var gearWheelIconDiv = adminActions[i];
var hyperlinksInAdminDialog = gearWheelIconDiv.getElementsByTagName('a');
var fbMemberId = gearWheelIconDiv.parentNode.parentNode.id.replace('member_','');
var fbMemberName = getTextFromElement(gearWheelIconDiv.parentNode.parentNode.getElementsByClassName('fcb')[0]);
if (excludedFbIds.indexOf(fbMemberId) != -1) {
console.log("SKIPPING "+fbMemberName+' ('+fbMemberId+')');
continue;
} else {
usersToDeleteQueue.push({'memberId': fbMemberId, 'gearWheelIconDiv': gearWheelIconDiv});
}
}
}
function processQueue() {
if (!scriptEnabled) {
return;
}
if (usersToDeleteQueue.length > 0) {
removeNext();
setTimeout(function(){
processQueue();
},1000);
} else {
getMore();
}
}
function removeNext() {
if (!scriptEnabled) {
return;
}
if (usersToDeleteQueue.length > 0) {
var nextElement = usersToDeleteQueue.pop();
removeMember(nextElement.memberId, nextElement.gearWheelIconDiv);
}
}
function removeMember(memberId, gearWheelIconDiv) {
if (processing) {
return;
}
var gearWheelHref = gearWheelIconDiv.getElementsByTagName('a')[0];
gearWheelHref.click();
processing = true;
setTimeout(function(){
var popupRef = gearWheelHref.id;
var popupDiv = getElementByAttribute('data-ownerid',popupRef);
var popupLinks = popupDiv.getElementsByTagName('a');
for(var j=0; j<popupLinks.length; j++) {
if (popupLinks[j].getAttribute('href').indexOf('remove.php') !== -1) {
// this is the remove link
popupLinks[j].click();
setTimeout(function(){
var confirmButton = document.getElementsByClassName('layerConfirm uiOverlayButton selected')[0];
var errorDialog = getElementByAttribute('data-reactid','.4.0');
if (confirmButton != null) {
if (canClick(confirmButton)) {
confirmButton.click();
} else {
console.log('This should not happen memberid: '+memberId);
5/0;
console.log(gearWheelIconDiv);
}
}
if (errorDialog != null) {
console.log("Error while removing member "+memberId);
errorDialog.getElementsByClassName('selected layerCancel autofocus')[0].click();
}
processing = false;
},700);
continue;
}
}
},500);
}
function canClick(el) {
return (typeof el != 'undefined') && (typeof el.click != 'undefined');
}
function getMore() {
processing = true;
more = document.getElementsByClassName("pam uiBoxLightblue uiMorePagerPrimary");
if (typeof more != 'undefined' && canClick(more[0])) {
more[0].click();
setTimeout(function(){
deleteAll();
processing = false;
}, 2000);
} else {
deleteAllGroupMembers.stop();
}
}
function getTextFromElement(element) {
var text = element.textContent;
return text;
}
function getElementByAttribute(attr, value, root) {
root = root || document.body;
if(root.hasAttribute(attr) && root.getAttribute(attr) == value) {
return root;
}
var children = root.children,
element;
for(var i = children.length; i--; ) {
element = getElementByAttribute(attr, value, children[i]);
if(element) {
return element;
}
}
return null;
}
return deleteAllGroupMembers;
})();
deleteAllGroupMembers.start();
// stop the script by entering this in the console: deleteAllGroupMembers.stop();
Use this in Chrome or Firefox Javascript control panel.
I am trying to retrieve the line number in dojo data grid. rowIndex function would not help me much because I need the 'line number' and NOT 'row number' when sorted.
The scenario:
I would like to set the focus on one specific row and this focus should remain even after sorting. But if I use the code below, it does not select the correct row.
For example, the index 1 is on the 5th line after sorting. However, the e.item.id still remains as 1, expected is 5.
calendar.on("itemClick", function (e)
{
MyGrid.doclick({ rowIndex: e.item.id });
MyGrid.scrollToRow(e.item.id);
});
Additionally, I also tried...
calendar.on("itemClick", function (e)
{
var identity = MyGrid._by_idx[e.item.id].idty;
var gridItem = MyGrid.getItem(identity);
var gridItemIndex = MyGrid.getItemIndex(gridItem);
MyGrid.doclick({ rowIndex: gridItemIndex });
MyGrid.scrollToRow(e.item.id);
});
Could you please let me know how to get the correct row after fitering? I thank you for your time.
Wishes,
Santosh
Okay, I figured out the answer.
GetGridItemIndexByGridItem = function (gridItem) {
var indexLength = MyGrid._by_idx.length;
var element = null;
var gridItemIndex = -1;
for (var i = 0; i < indexLength; i++) {
element = MyGrid._by_idx[i];
if (element.item.Guid == gridItem.Guid) {
gridItemIndex = i;
}
}
return gridItemIndex;
}
Best Wishes
I am currently implementing a custom data source in a Windows8 application. However, I got some trouble with it: no data is displayed.
First, here is the code:
var dataArray = [
{ title: "Basic banana", text: "Low-fat frozen yogurt", picture: "images/60banana.png" },
// Other data taken from Windows8 ListView quick start
{ title: "Succulent strawberry", text: "Sorbet", picture: "images/60strawberry.png" }
];
var searchAdDataAdapter = WinJS.Class.define(
function () {}, // Constructor
{
itemsFromIndex: function (requestIndex, countBefore, countAfter) {
var that = this;
if (requestIndex >= that._maxCount) {
return WinJS.Promise.wrapError(new WinJS.ErrorFromName(UI.FetchError.doesNotExist));
}
var fetchSize, fetchIndex;
// See which side of the requestIndex is the overlap.
if (countBefore > countAfter) {
// Limit the overlap
countAfter = Math.min(countAfter, 10);
// Bound the request size based on the minimum and maximum sizes.
var fetchBefore = Math.max(
Math.min(countBefore, that._maxPageSize - (countAfter + 1)),
that._minPageSize - (countAfter + 1)
);
fetchSize = fetchBefore + countAfter + 1;
fetchIndex = requestIndex - fetchBefore;
} else {
countBefore = Math.min(countBefore, 10);
var fetchAfter = Math.max(Math.min(countAfter, that._maxPageSize - (countBefore + 1)), that._minPageSize - (countBefore + 1));
fetchSize = countBefore + fetchAfter + 1;
fetchIndex = requestIndex - countBefore;
}
// Create an array of IItem objects:
// results =[{ key: key1, data : { field1: value, field2: value, ... }}, { key: key2, data : {...}}, ...];
for (var i = 0, itemsLength = dataArray.length ; i < itemsLength ; i++) {
var dataItem = dataArray[i];
results.push({
key: (fetchIndex + i).toString(),
data: dataArray[i]
});
}
// Get the count.
count = dataArray.length;
return {
items: results, // The array of items.
offset: requestIndex - fetchIndex, // The index of the requested item in the items array.
totalCount: count
};
},
getCount: function () {
return dataArray.length;
}
}
);
var searchAdDataSource = WinJS.Class.derive(WinJS.UI.VirtualizedDataSource, function () {
this._baseDataSourceConstructor(new searchAdDataAdapter());
});
// Create a namespace to make the data publicly
// accessible.
var publicMembers = {
itemList: new searchAdDataSource()
};
WinJS.Namespace.define("DataExample", publicMembers);
I know the code is a little bit long, but the major part of it is taken from official Microsoft custom data source quick start.
I tried to debug it, but it seems the code contained in itemFromIndex is never used (my breakpoint is never reached).
The HTML code is:
<div id="basicListView" data-win-control="WinJS.UI.ListView"
data-win-options="{itemDataSource : DataExample.itemList.dataSource}">
</div>
I do not use any template for the moment, to simplify the code as more as I can. Data are normally displayed in text this way (but nothing appears).
Have one of this great community any idea?
Furthermore, I do not understand the countBefore and countAfter parameters, even with the documentation. Can somebody explain it to me with other words?
Thanks a lot! :)
Try modifying your HTML code to the following:
<div id="basicListView" data-win-control="WinJS.UI.ListView"
data-win-options="{itemDataSource : DataExample.itemList}">
</div>
No need to call the .datasource member, as you are talking to the datasource directly.