I'm writing some Firefox add-on code that manipulates the user's bookmarks.
I started with the "Searching Bookmarks" code from https://developer.mozilla.org/En/Places_Developer_Guide, and ended up writing the following code, which works...
var folders = [bookmarksService.bookmarksMenuFolder, bookmarksService.toolbarFolder, bookmarksService.unfiledBookmarksFolder];
var bookmarks = [];
for (var i = 0; i < 3; i++) {
query.setFolders([folders[i]], 1);
var result = historyService.executeQuery(query, options);
var rootNode = result.root;
rootNode.containerOpen = true;
getNode(rootNode, bookmarks);
rootNode.containerOpen = false;
}
The problem with this code is that it hard-codes the 3 default bookmark folders. I'd like the code to handle the case in which the user has created their own bookmark folders.
How can this code be changed so that it loops over all of the bookmark folders?
I think you're getting confused with the "folder" terminology here. The three hard-coded items you have in your code block are all you need. Any bookmarks the user creates will be located in one of these three places. You can see this in action by opening up the bookmarks editor in Firefox (Ctrl + Shift + B). In the tree pane on the left, select the All Bookmarks item, and note that there are only 3 (possibly 4) items underneath it:
Bookmarks Toolbar
Bookmarks Menu
Unsorted Bookmarks
If you right-click the "All Bookmarks" top-level item, you'll note that there is no "Create Folder" option at this level. Any user-created bookmarks are below the sub-items listed at this level.
The Places Developer Guide lists one additional top-level folder (tagsFolder), but I don't think you need to worry about that one. I can't imagine a bookmark existing there and not in one of the other three locations.
Related
I have the following javascript code that works at the document level in Adobe Acrobat 10 when the document is opened (enveloped in this.addScript):
var nNumFields = this.numFields;
var cFieldName;
var oField;
for(i = 0; i < nNumFields; i++)
{
cFieldName = this.getNthFieldName(i);
oField = this.getField(cFieldName);
oField.textFont = \"PTSans\";
}
I want to avoid going through multiple documents and adding this script to all of them. Is there a way to adapt this code to the folder level so it works for all acrobat opened documents?? If so what would it be?
Or is there a way to add this script for a list of documents quickly (programmatically) instead of manually?? (manually as in by opening the document, inserting the script into the debugger, running it, then saving the document, then repeating for every document)
For many reasons it isn't always ideal to install a plugin on multiple sites just to copy content. For pages / posts it's really easy to grab the post content and copy+paste (even when using page builders the content is available in an underlying textarea). Menus on the other hand are a pain. What is your goto method for copying menus?
This is what I whipped up today to solve copying WordPress menus via JavaScript / without a plugin.
First navigate to the menu you want to copy and paste this into the console.
var items = jQuery('#menu-to-edit li');
var json = [];
jQuery.each(items, function(i, item) {
item = jQuery(item);
var title = item.find('.edit-menu-item-title').val();
var url = item.find('.edit-menu-item-url').val();
var classes = item.find('.edit-menu-item-classes').val();
var description = item.find('.edit-menu-item-description').val();
var menuitem = {"title" : title, "url" : url, "classes" : classes, "description" : description};
json.push(menuitem);
});
JSON.stringify(json);
Copy that output and navigate to the new menu - paste the content into the parse statement below:
var json = JSON.parse('PASTED DATA HERE');
function addItem(item)
{
jQuery('#custom-menu-item-url').val(item.url);
if (item.url == "")
{
item.url = "#";
}
jQuery('#custom-menu-item-name').val(item.title);
jQuery('#submit-customlinkdiv').click();
}
Then simply shift elements out of that json element and into the addItem function.
addItem(json.shift());
Rinse and repeat until your items are added.
There is lots of room for optimization on this e.g. it could add the classes / descriptions, re-order the menu items in the correct depth, add extended properties or monitor the add menu item form and automatically add the next item for you - could become a handy bookmarklet to beat back throwaway plugins like those that do simple menu copies.
is there a way to check if the user has more than one tab open (not globally, only on my website) or how many tabs the user has open?
In the best case i need the amount but a boolean value would be enough.
I need a solution in vanilla JavaScript (ES6) without jQuery or something else.
Thank you in advance.
You could create an ID for every opened tab and save it in an array in the localStorage (document.cookie would also work, but requires a bit more effort with getting and setting):
var tabId = Math.random();
var tabs = JSON.parse(localStorage.getItem('tabs')) || [];
tabs.push(tabId);
localStorage.setItem('tabs', JSON.stringify(tabs));
Now, to check how many tabs we have open on the current domain, we check the length of the tabs array in the localStorage:
function getTabCount()
{
return JSON.parse(localStorage.getItem('tabs')).length;
}
Now, you can use getTabCount() to get the amount of tabs that are currently open.
Finally, we need to make sure our tabId is removed from the array when we close it:
window.addEventListener('beforeunload', function(e)
{
tabs = JSON.parse(localStorage.getItem('tabs'));
var index = tabs.indexOf(tabId);
if (index !== -1)
tabs.splice(index, 1);
localStorage.setItem('tabs', JSON.stringify(tabs));
});
Do keep in mind that you need to keep using getTabCount() to check if any tabs have been opened or closed since you last used it.
I need to show list of data , at least 1 million rows (Big data , machine learning).
I do not need to show at once , remotetablemodel of qooxdoo table works fine but instead of table i choose list as design choice.
Below is a test i've made.
//create the model data, 1mil items
var rawData = [];
for (var i = 0; i < 1000000; i++) {
rawData[i] = "Item No " + i;
}
var model = new qx.data.Array(rawData);
//create the list
var list = new qx.ui.list.List(model);
this.getRoot().add(list);
I understand the point that it will take long to generate rawdata and assign it to list.
But the problem is after assigning the list , the virtual list itself is almost non-responsive.
Scrolling is very slow , navigating by down arrow freezes a few secs too.
Qooxdoo virtual infrastructure is suppose to render only visible items if i understand correctly? But in above test case it is so slow.
I expect to work like remote table model .
Tested with qooxdoo latest 4.0.0 and 3.5.1 , on Chrome 35 stable.
I can reproduce you issue only with the source version and not with the build version. I found the reason why the performance is so slow. There is an runtime check in an internal method from the SingleValueBinding which has a huge performance impact on the rendering.
I opened a bug report for that:
http://bugzilla.qooxdoo.org/show_bug.cgi?id=8439
But as I sad this issue only occurs with your developer version. So your customers are not effected.
You can disable the check if you want. Just remove the check block:
https://github.com/qooxdoo/qooxdoo/blob/master/framework/source/class/qx/data/SingleValueBinding.js#L915
You can also load your model data in parts to improve the model creation. You can maybe load the next part when the user has scrolled to the end of the list. You can use the example you have already seen:
Infinite scroll in qooxdoo with virtual list
just a very short question on using Backbone.js with LocalStorage:
I'm storing a list of things (Backbone collection) in LocalStorage. When my website is open in multiple browser windows / tabs and the user in both windows adds something to the list, one window's changes will overwrite the changes made in the other window.
If you want to try for yourself, just use the example Backbone.js Todo app:
Open http://backbonejs.org/examples/todos/index.html in two browser tabs
Add an item 'item1' in the first tab and 'item2' in the second tab
Refresh both tabs: 'item1' will disappear and you'll be left with 'item2' only
Any suggestions how to prevent this from happening, any standard way to deal with this?
Thxx
The issue is well-known concurrency lost updates problem, see Lost update in Concurrency control?.
Just for your understanding I might propose the following quick and dirty fix, file backbone-localstorage.js, Store.prototype.save:
save: function() {
// reread data right before writing
var store = localStorage.getItem(this.name);
var data = (store && JSON.parse(store)) || {};
// we may choose what is overwritten with what here
_.extend(this.data, data);
localStorage.setItem(this.name, JSON.stringify(this.data));
}
For the latest Github version of Backbone localStorage, I think this should look like this:
save: function() {
var store = this.localStorage().getItem(this.name);
var records = (store && store.split(",")) || [];
var all = _.union(records, this.records);
this.localStorage().setItem(this.name, all.join(","));
}
You may want to use sessionStorage instead.
See http://en.wikipedia.org/wiki/Web_storage#Local_and_session_storage.
Yaroslav's comment about checking for changes before persisting new ones is one solution but my suggestion would be different. Remember that localStorage is capable of firing events when it performs actions that change the data it holds. Bind to those events and have each tab listen for those changes and view re-render after it happens.
Then, when I make deletions or additions in one tab and move over to the next, it will get an event and change to reflect what happened in the other tab. There won't be weird discrepancies in what I'm seeing tab to tab.
You will want to give some thought to making sure that I don't lose something I was in the middle of adding (say I start typing a new entry for my to-do list), switch to another tab and delete something, and then come back I want to see the entry disappear but my partially typed new item should still be available for me.