Merge fx-team to m-c a=merge

This commit is contained in:
Wes Kocher 2014-10-08 16:46:52 -07:00
commit b2cbe8c0b3
21 changed files with 292 additions and 191 deletions

View File

@ -398,8 +398,7 @@ panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .a
visibility: visible;
}
#urlbar:not([actiontype]) > #urlbar-display-box,
#urlbar:not([actiontype="switchtab"]) > #urlbar-display-box > .urlbar-display-switchtab {
#urlbar:not([actiontype="switchtab"]) > #urlbar-display-box {
display: none;
}

View File

@ -425,7 +425,7 @@ this.GoogleImporter.prototype = {
if (Object.keys(adr).length) {
adr.pref = (addressNode.getAttribute("primary") == "true");
adr.type = [getFieldType(addressNode)];
contacts.adr.push(adr);
contact.adr.push(adr);
}
}
}

View File

@ -58,6 +58,13 @@
// Local mocks
var mockContact = {
name: ["Mr Smith"],
email: [{
value: "smith@invalid.com"
}]
};
var mockClient = {
requestCallUrl: noop,
requestCallUrlInfo: noop
@ -254,7 +261,8 @@
Example({summary: "Connecting", dashed: "true",
style: {width: "260px", height: "265px"}},
React.DOM.div({className: "fx-embedded"},
DesktopPendingConversationView({callState: "gather", calleeId: "Mr Smith"})
DesktopPendingConversationView({callState: "gather",
contact: mockContact})
)
)
),

View File

@ -58,6 +58,13 @@
// Local mocks
var mockContact = {
name: ["Mr Smith"],
email: [{
value: "smith@invalid.com"
}]
};
var mockClient = {
requestCallUrl: noop,
requestCallUrlInfo: noop
@ -254,7 +261,8 @@
<Example summary="Connecting" dashed="true"
style={{width: "260px", height: "265px"}}>
<div className="fx-embedded">
<DesktopPendingConversationView callState={"gather"} calleeId="Mr Smith" />
<DesktopPendingConversationView callState={"gather"}
contact={mockContact} />
</div>
</Example>
</Section>

View File

@ -191,7 +191,7 @@ public class BrowserApp extends GeckoApp
public boolean added; // So we can re-add after a locale change.
}
// The types of guest mdoe dialogs we show
// The types of guest mode dialogs we show.
public static enum GuestModeDialog {
ENTERING,
LEAVING
@ -520,11 +520,12 @@ public class BrowserApp extends GeckoApp
mAboutHomeStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_ABOUTHOME");
final Intent intent = getIntent();
final String args = intent.getStringExtra("args");
if (GuestSession.shouldUse(this, args)) {
mProfile = GeckoProfile.createGuestProfile(this);
} else {
final GeckoProfile p = GeckoProfile.get(this);
if (p != null && !p.inGuestMode()) {
// This is *only* valid because we never want to use the guest mode
// profile concurrently with a normal profile -- no syncing to it,
// no dual-profile usage, nothing. BrowserApp startup with a conventional
// GeckoProfile will cause the guest profile to be deleted.
GeckoProfile.maybeCleanupGuestProfile(this);
}
@ -673,13 +674,6 @@ public class BrowserApp extends GeckoApp
Log.e(LOGTAG, "Error initializing media manager", ex);
}
}
if (getProfile().inGuestMode()) {
GuestSession.showNotification(this);
} else {
// If we're restarting, we won't destroy the activity. Make sure we remove any guest notifications that might have been shown.
GuestSession.hideNotification(this);
}
}
private void setupSystemUITinting() {
@ -790,6 +784,35 @@ public class BrowserApp extends GeckoApp
lbm.unregisterReceiver(mOnboardingReceiver);
}
@Override
public void onStart() {
super.onStart();
// Queue this work so that the first launch of the activity doesn't
// trigger profile init too early.
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
if (getProfile().inGuestMode()) {
GuestSession.showNotification(BrowserApp.this);
} else {
// If we're restarting, we won't destroy the activity.
// Make sure we remove any guest notifications that might
// have been shown.
GuestSession.hideNotification(BrowserApp.this);
}
}
});
}
@Override
public void onStop() {
super.onStop();
// We only show the guest mode notification when our activity is in the foreground.
GuestSession.hideNotification(this);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
@ -1087,8 +1110,6 @@ public class BrowserApp extends GeckoApp
mBrowserHealthReporter = null;
}
GuestSession.onDestroy(this);
EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener)this,
"Menu:Update",
"Reader:Added",
@ -2939,6 +2960,9 @@ public class BrowserApp extends GeckoApp
args = GUEST_BROWSING_ARG;
} else {
GeckoProfile.leaveGuestSession(BrowserApp.this);
// Now's a good time to make sure we're not displaying the Guest Browsing notification.
GuestSession.hideNotification(BrowserApp.this);
}
if (!GuestSession.isSecureKeyguardLocked(BrowserApp.this)) {

View File

@ -193,7 +193,8 @@ class ChromeCast implements GeckoMediaPlayer {
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(Bundle connectionHint) {
if (!apiClient.isConnected()) {
// Sometimes apiClient is null here. See bug 1061032
if (apiClient != null && !apiClient.isConnected()) {
debug("Connection failed");
callback.sendError("Not connected");
return;
@ -253,18 +254,23 @@ class ChromeCast implements GeckoMediaPlayer {
return;
}
remoteMediaPlayer.play(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
@Override
public void onResult(MediaChannelResult result) {
Status status = result.getStatus();
if (!status.isSuccess()) {
debug("Unable to play: " + status.getStatusCode());
callback.sendError(status.toString());
} else {
callback.sendSuccess(null);
try {
remoteMediaPlayer.play(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
@Override
public void onResult(MediaChannelResult result) {
Status status = result.getStatus();
if (!status.isSuccess()) {
debug("Unable to play: " + status.getStatusCode());
callback.sendError(status.toString());
} else {
callback.sendSuccess(null);
}
}
}
});
});
} catch(IllegalStateException ex) {
// The media player may throw if the session has been killed. For now, we're just catching this here.
callback.sendError("Error playing");
}
}
public void pause(final EventCallback callback) {
@ -272,18 +278,23 @@ class ChromeCast implements GeckoMediaPlayer {
return;
}
remoteMediaPlayer.pause(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
@Override
public void onResult(MediaChannelResult result) {
Status status = result.getStatus();
if (!status.isSuccess()) {
debug("Unable to pause: " + status.getStatusCode());
callback.sendError(status.toString());
} else {
callback.sendSuccess(null);
try {
remoteMediaPlayer.pause(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
@Override
public void onResult(MediaChannelResult result) {
Status status = result.getStatus();
if (!status.isSuccess()) {
debug("Unable to pause: " + status.getStatusCode());
callback.sendError(status.toString());
} else {
callback.sendSuccess(null);
}
}
}
});
});
} catch(IllegalStateException ex) {
// The media player may throw if the session has been killed. For now, we're just catching this here.
callback.sendError("Error pausing");
}
}
public void end(final EventCallback callback) {
@ -291,32 +302,37 @@ class ChromeCast implements GeckoMediaPlayer {
return;
}
Cast.CastApi.stopApplication(apiClient).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status result) {
if (result.isSuccess()) {
try {
Cast.CastApi.removeMessageReceivedCallbacks(apiClient, remoteMediaPlayer.getNamespace());
remoteMediaPlayer = null;
mSessionId = null;
apiClient.disconnect();
apiClient = null;
try {
Cast.CastApi.stopApplication(apiClient).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status result) {
if (result.isSuccess()) {
try {
Cast.CastApi.removeMessageReceivedCallbacks(apiClient, remoteMediaPlayer.getNamespace());
remoteMediaPlayer = null;
mSessionId = null;
apiClient.disconnect();
apiClient = null;
if (callback != null) {
callback.sendSuccess(null);
if (callback != null) {
callback.sendSuccess(null);
}
return;
} catch(Exception ex) {
debug("Error ending", ex);
}
}
return;
} catch(Exception ex) {
debug("Error ending", ex);
if (callback != null) {
callback.sendError(result.getStatus().toString());
}
}
if (callback != null) {
callback.sendError(result.getStatus().toString());
}
}
});
});
} catch(IllegalStateException ex) {
// The media player may throw if the session has been killed. For now, we're just catching this here.
callback.sendError("Error stopping");
}
}
class MirrorChannel implements MessageReceivedCallback {
@ -413,7 +429,8 @@ class ChromeCast implements GeckoMediaPlayer {
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(Bundle connectionHint) {
if (!apiClient.isConnected()) {
// Sometimes apiClient is null here. See bug 1061032
if (apiClient == null || !apiClient.isConnected()) {
return;
}

View File

@ -9,7 +9,6 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
@ -45,7 +44,6 @@ import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.preferences.ClearOnShutdownPref;
import org.mozilla.gecko.preferences.GeckoPreferences;
import org.mozilla.gecko.prompts.PromptService;
import org.mozilla.gecko.SmsManager;
import org.mozilla.gecko.updater.UpdateService;
import org.mozilla.gecko.updater.UpdateServiceHelper;
import org.mozilla.gecko.util.ActivityResultHandler;
@ -443,6 +441,9 @@ public abstract class GeckoApp
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.quit) {
// Make sure the Guest Browsing notification goes away when we quit.
GuestSession.hideNotification(this);
if (GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.GeckoRunning, GeckoThread.LaunchState.GeckoExiting)) {
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(this);
final Set<String> clearSet = PrefUtils.getStringSet(prefs, ClearOnShutdownPref.PREF, new HashSet<String>());

View File

@ -23,6 +23,7 @@ import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.util.INIParser;
import org.mozilla.gecko.util.INISection;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@ -90,9 +91,19 @@ public final class GeckoProfile {
}
}
// If the guest profile should be used return it.
if (GuestSession.shouldUse(context, "")) {
return GeckoProfile.getGuestProfile(context);
final String args;
if (context instanceof Activity) {
args = ((Activity) context).getIntent().getStringExtra("args");
} else {
args = null;
}
if (GuestSession.shouldUse(context, args)) {
GeckoProfile p = GeckoProfile.getOrCreateGuestProfile(context);
if (isGeckoApp) {
((GeckoApp) context).mProfile = p;
}
return p;
}
if (isGeckoApp) {
@ -191,6 +202,8 @@ public final class GeckoProfile {
return success;
}
// Only public for access from tests.
@RobocopTarget
public static GeckoProfile createGuestProfile(Context context) {
try {
// We need to force the creation of a new guest profile if we want it outside of the normal profile path,
@ -232,6 +245,18 @@ public final class GeckoProfile {
return sGuestDir;
}
/**
* Performs IO. Be careful of using this on the main thread.
*/
public static GeckoProfile getOrCreateGuestProfile(Context context) {
GeckoProfile p = getGuestProfile(context);
if (p == null) {
return createGuestProfile(context);
}
return p;
}
public static GeckoProfile getGuestProfile(Context context) {
if (sGuestProfile == null) {
File guestDir = getGuestDir(context);

View File

@ -4,29 +4,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import android.app.NotificationManager;
import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.util.Log;
import android.support.v4.app.NotificationCompat;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ListView;
import android.support.v4.app.NotificationCompat;
import org.mozilla.gecko.prompts.Prompt;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.NativeEventListener;
import org.mozilla.gecko.util.NativeJSObject;
import org.mozilla.gecko.util.ThreadUtils;
import java.io.File;
import org.json.JSONException;
import org.json.JSONObject;
// Utility methods for entering/exiting guest mode.
public class GuestSession {
@ -105,12 +91,6 @@ public class GuestSession {
manager.cancel(R.id.guestNotification);
}
public static void onDestroy(Context context) {
if (GeckoProfile.get(context).inGuestMode()) {
hideNotification(context);
}
}
public static void handleIntent(BrowserApp context, Intent intent) {
context.showGuestModeDialog(BrowserApp.GuestModeDialog.LEAVING);
}

View File

@ -182,7 +182,7 @@
<!ENTITY pref_char_encoding_off "Don\'t show menu">
<!ENTITY pref_clear_private_data2 "Clear now">
<!ENTITY pref_clear_private_data_category "Clear private data">
<!ENTITY pref_clear_on_exit_title "Always clear when quitting">
<!ENTITY pref_clear_on_exit_title2 "Clear on exit">
<!ENTITY pref_clear_on_exit_summary2 "&brandShortName; will automatically clear your data whenever you select \u0022Quit\u0022 from the main menu">
<!ENTITY pref_clear_on_exit_dialog_title "Select which data to clear">
<!ENTITY pref_plugins "Plugins">

View File

@ -191,7 +191,7 @@
<string name="pref_char_encoding_off">&pref_char_encoding_off;</string>
<string name="pref_clear_private_data">&pref_clear_private_data2;</string>
<string name="pref_clear_private_data_category">&pref_clear_private_data_category;</string>
<string name="pref_clear_on_exit_title">&pref_clear_on_exit_title;</string>
<string name="pref_clear_on_exit_title">&pref_clear_on_exit_title2;</string>
<string name="pref_clear_on_exit_summary2">&pref_clear_on_exit_summary2;</string>
<string name="pref_clear_on_exit_dialog_title">&pref_clear_on_exit_dialog_title;</string>
<string name="pref_plugins">&pref_plugins;</string>

View File

@ -55,7 +55,7 @@ class TabsGridLayout extends GridView
@Override
public void onMovedToScrapHeap(View view) {
TabsLayoutItemView item = (TabsLayoutItemView) view;
item.thumbnail.setImageDrawable(null);
item.setThumbnail(null);
}
});
}
@ -72,7 +72,7 @@ class TabsGridLayout extends GridView
@Override
public void onClick(View v) {
TabsLayoutItemView itemView = (TabsLayoutItemView) v.getTag();
Tab tab = Tabs.getInstance().getTab(itemView.id);
Tab tab = Tabs.getInstance().getTab(itemView.getTabId());
Tabs.getInstance().closeTab(tab);
}
};
@ -81,7 +81,7 @@ class TabsGridLayout extends GridView
@Override
public void onClick(View v) {
TabsLayoutItemView tab = (TabsLayoutItemView) v;
Tabs.getInstance().selectTab(tab.id);
Tabs.getInstance().selectTab(tab.getTabId());
autoHidePanel();
}
};

View File

@ -24,13 +24,11 @@ public class TabsLayoutItemView extends LinearLayout
private static final int[] STATE_CHECKED = { android.R.attr.state_checked };
private boolean mChecked;
// yeah, it's a bit nasty having two different styles for the class members,
// this'll be fixed once bug 1058574 is addressed
int id;
TextView title;
ImageView thumbnail;
ImageButton close;
TabThumbnailWrapper thumbnailWrapper;
private int mTabId;
private TextView mTitle;
private ImageView mThumbnail;
private ImageButton mCloseButton;
private TabThumbnailWrapper mThumbnailWrapper;
public TabsLayoutItemView(Context context, AttributeSet attrs) {
super(context, attrs);
@ -76,16 +74,16 @@ public class TabsLayoutItemView extends LinearLayout
}
public void setCloseOnClickListener(OnClickListener mOnClickListener) {
close.setOnClickListener(mOnClickListener);
mCloseButton.setOnClickListener(mOnClickListener);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
title = (TextView) findViewById(R.id.title);
thumbnail = (ImageView) findViewById(R.id.thumbnail);
close = (ImageButton) findViewById(R.id.close);
thumbnailWrapper = (TabThumbnailWrapper) findViewById(R.id.wrapper);
mTitle = (TextView) findViewById(R.id.title);
mThumbnail = (ImageView) findViewById(R.id.thumbnail);
mCloseButton = (ImageButton) findViewById(R.id.close);
mThumbnailWrapper = (TabThumbnailWrapper) findViewById(R.id.wrapper);
}
protected void assignValues(Tab tab) {
@ -93,18 +91,30 @@ public class TabsLayoutItemView extends LinearLayout
return;
}
id = tab.getId();
mTabId = tab.getId();
Drawable thumbnailImage = tab.getThumbnail();
if (thumbnailImage != null) {
thumbnail.setImageDrawable(thumbnailImage);
mThumbnail.setImageDrawable(thumbnailImage);
} else {
thumbnail.setImageResource(R.drawable.tab_thumbnail_default);
mThumbnail.setImageResource(R.drawable.tab_thumbnail_default);
}
if (thumbnailWrapper != null) {
thumbnailWrapper.setRecording(tab.isRecording());
if (mThumbnailWrapper != null) {
mThumbnailWrapper.setRecording(tab.isRecording());
}
title.setText(tab.getDisplayTitle());
close.setTag(this);
mTitle.setText(tab.getDisplayTitle());
mCloseButton.setTag(this);
}
public int getTabId() {
return mTabId;
}
public void setThumbnail(Drawable thumbnail) {
mThumbnail.setImageDrawable(thumbnail);
}
public void setCloseVisibile(boolean visible) {
mCloseButton.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
}
}

View File

@ -80,8 +80,8 @@ class TabsListLayout extends TwoWayView
@Override
public void onMovedToScrapHeap(View view) {
TabsLayoutItemView item = (TabsLayoutItemView) view;
item.thumbnail.setImageDrawable(null);
item.close.setVisibility(View.VISIBLE);
item.setThumbnail(null);
item.setCloseVisibile(true);
}
});
}
@ -360,7 +360,7 @@ class TabsListLayout extends TwoWayView
else
animator.attach(view, Property.WIDTH, 1);
final int tabId = ((TabsLayoutItemView) view).id;
final int tabId = ((TabsLayoutItemView) view).getTabId();
// Caching this assumes that all rows are the same height
if (mOriginalSize == 0) {
@ -397,7 +397,7 @@ class TabsListLayout extends TwoWayView
@Override
public void onPropertyAnimationEnd() {
TabsLayoutItemView tab = (TabsLayoutItemView) view;
tab.close.setVisibility(View.VISIBLE);
tab.setCloseVisibile(true);
}
});
@ -495,7 +495,7 @@ class TabsListLayout extends TwoWayView
if (!mSwiping) {
TabsLayoutItemView item = (TabsLayoutItemView) mSwipeView;
Tabs.getInstance().selectTab(item.id);
Tabs.getInstance().selectTab(item.getTabId());
autoHidePanel();
mVelocityTracker.recycle();
@ -582,7 +582,7 @@ class TabsListLayout extends TwoWayView
mSwiping = true;
TabsListLayout.this.requestDisallowInterceptTouchEvent(true);
((TabsLayoutItemView) mSwipeView).close.setVisibility(View.INVISIBLE);
((TabsLayoutItemView) mSwipeView).setCloseVisibile(false);
// Stops listview from highlighting the touched item
// in the list when swiping.

View File

@ -119,7 +119,7 @@ HelperAppLauncherDialog.prototype = {
Services.console.logStringMessage("Refusing download of non-downloadable file.");
let bundle = Services.strings.createBundle("chrome://browser/locale/handling.properties");
let failedText = bundle.GetStringFromName("protocol.failed");
let failedText = bundle.GetStringFromName("download.blocked");
win.toast.show(failedText, "long");
return;

View File

@ -2,6 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
download.blocked=Unable to download file
protocol.failed=Couldn't find an app to open this link
# A very short string shown in the button toast when no application can open the url
protocol.toast.search=Search

View File

@ -142,9 +142,10 @@ class XPCShellRunner(MozbuildObject):
modules_dir = os.path.join(self.topobjdir, '_tests', 'modules')
# We want output from the test to be written immediately if we are only
# running a single test.
verbose_output = (test_path is not None or
(manifest and len(manifest.test_paths())==1) or
verbose)
single_test = (test_path is not None or
(manifest and len(manifest.test_paths())==1))
verbose_output = verbose or single_test
sequential = sequential or single_test
args = {
'manifest': manifest,

View File

@ -7,8 +7,8 @@
/**
* This module provides an asynchronous API for managing bookmarks.
*
* Bookmarks are organized in a tree structure, and can be bookmarked URIs,
* folders or separators. Multiple bookmarks for the same URI are allowed.
* Bookmarks are organized in a tree structure, and can be bookmarked URLs,
* folders or separators. Multiple bookmarks for the same URL are allowed.
*
* Note that if you are handling bookmarks operations in the UI, you should
* not use this API directly, but rather use PlacesTransactions.jsm, so that
@ -24,10 +24,10 @@
* This will be an empty string for the Places root folder.
* - index (number)
* The 0-based position of the item in the parent folder.
* - dateAdded (number, microseconds from the epoch)
* The time at which the item was added. This is a PRTime (microseconds).
* - lastModified (number, microseconds from the epoch)
* The time at which the item was last modified. This is a PRTime (microseconds).
* - dateAdded (Date)
* The time at which the item was added.
* - lastModified (Date)
* The time at which the item was last modified.
* - type (number)
* The item's type, either TYPE_BOOKMARK, TYPE_FOLDER or TYPE_SEPARATOR.
*
@ -36,11 +36,16 @@
* - title (string)
* The item's title, if any. Empty titles and null titles are considered
* the same and the property is unset on retrieval in such a case.
* Title cannot be longer than TITLE_LENGTH_MAX, or it will be truncated.
*
* The following properties are only valid for bookmarks:
*
* - uri (nsIURI)
* The item's URI.
* - url (URL, href or nsIURI)
* The item's URL. Note that while input objects can contains either
* an URL object, an href string, or an nsIURI, output objects will always
* contain an URL object.
* URL cannot be longer than URL_LENGTH_MAX, methods will throw if a
* longer value is provided
* - keyword (string)
* The associated keyword, if any.
*
@ -53,9 +58,6 @@
* property) won't fire an onItemChanged notification for the lastModified
* property.
* @see nsINavBookmarkObserver
*
* @note livemarks are implemented as empty folders.
* @see mozIAsyncLivemarks.idl
*/
this.EXPORTED_SYMBOLS = [ "Bookmarks" ];
@ -74,7 +76,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
"resource://gre/modules/Sqlite.jsm");
const URI_LENGTH_MAX = 65536;
const URL_LENGTH_MAX = 65536;
const TITLE_LENGTH_MAX = 4096;
let Bookmarks = Object.freeze({
@ -86,6 +88,12 @@ let Bookmarks = Object.freeze({
TYPE_FOLDER: 2,
TYPE_SEPARATOR: 3,
/**
* Default index used to append a bookmarked item at the end of a container.
* This should stay consistent with nsINavBookmarksService.idl
*/
DEFAULT_INDEX: -1,
/**
* Creates or updates a bookmarked item.
*
@ -96,7 +104,7 @@ let Bookmarks = Object.freeze({
* In the creation case, a minimum set of properties must be provided:
* - type
* - parentGuid
* - URI, only for bookmarks
* - url, only for bookmarks
* If an index is not specified, it defaults to appending.
* It's also possible to pass a non-existent guid to force creation of an
* item with the given guid, but unless you have a very sound reason, such as
@ -111,17 +119,19 @@ let Bookmarks = Object.freeze({
* associated with this bookmark.
*
* Note that any known property that doesn't apply to the specific item type
* causes rejection.
* throws an exception.
*
* @param info
* object representing a bookmarked item, as defined above.
* @param onResult [optional]
* Callback invoked for each created or updated bookmark. It gets
* the bookmark object as argument.
*
* @return {Promise} resolved when the update is complete.
* @resolves to the input object, updated with relevant information.
* @rejects JavaScript exception.
*
* @note title is truncated to TITLE_LENGTH_MAX and URI is rejected if
* greater than URI_LENGTH_MAX.
* @resolves to a boolean indicating whether any new bookmark has been created.
* @rejects JavaScript exception if it's not possible to update or create the
* requested bookmark.
* @throws if input is invalid.
*/
// XXX WIP XXX Will replace functionality from these methods:
// long long insertBookmark(in long long aParentId, in nsIURI aURI, in long aIndex, in AUTF8String aTitle, [optional] in ACString aGUID);
@ -133,9 +143,9 @@ let Bookmarks = Object.freeze({
// void setItemLastModified(in long long aItemId, in PRTime aLastModified);
// void changeBookmarkURI(in long long aItemId, in nsIURI aNewURI);
// void setKeywordForBookmark(in long long aItemId, in AString aKeyword);
update: Task.async(function* (info) {
update: function (info, onResult=null) {
throw new Error("Not yet implemented");
}),
},
/**
* Removes a bookmarked item.
@ -145,25 +155,30 @@ let Bookmarks = Object.freeze({
* - guid: if set, only the corresponding item is removed.
* - parentGuid: if it's set and is a folder, any children of that folder is
* removed, but not the folder itself.
* - URI: if set, any bookmark for that URI is removed.
* If multiple of these properties are set, the method rejects.
* - url: if set, any bookmark for that URL is removed.
* If multiple of these properties are set, the method throws.
*
* Any other property is ignored, known properties may be overwritten.
*
* @param guidOrInfo
* The globally unique identifier of the item to remove, or an
* object representing it, as defined above.
* @param onResult [optional]
* Callback invoked for each removed bookmark. It gets the bookmark
* object as argument.
*
* @return {Promise} resolved when the removal is complete.
* @resolves to the removed object or an array of them.
* @rejects JavaScript exception.
* @resolves to a boolean indicating whether any object has been removed.
* @rejects JavaScript exception if the provided guid or parentGuid don't
* match any existing bookmark.
* @throws if input is invalid.
*/
// XXX WIP XXX Will replace functionality from these methods:
// removeItem(in long long aItemId);
// removeFolderChildren(in long long aItemId);
remove: Task.async(function* (guidOrInfo) {
remove: function (guidOrInfo, onResult=null) {
throw new Error("Not yet implemented");
}),
},
/**
* Fetches information about a bookmarked item.
@ -174,10 +189,10 @@ let Bookmarks = Object.freeze({
* retrieves the item with the specified guid
* - parentGuid and index
* retrieves the item by its position
* - URI
* retrieves all items having the given URI.
* - url
* retrieves an array of items having the given URL.
* - keyword
* retrieves all items having the given keyword.
* retrieves an array of items having the given keyword.
*
* Any other property is ignored. Known properties may be overwritten.
*
@ -190,6 +205,7 @@ let Bookmarks = Object.freeze({
* an array of such objects. if no item is found, the returned
* promise is resolved to null.
* @rejects JavaScript exception.
* @throws if input is invalid.
*/
// XXX WIP XXX Will replace functionality from these methods:
// long long getIdForItemAt(in long long aParentId, in long aIndex);
@ -205,16 +221,16 @@ let Bookmarks = Object.freeze({
// AString getKeywordForURI(in nsIURI aURI);
// AString getKeywordForBookmark(in long long aItemId);
// nsIURI getURIForKeyword(in AString keyword);
fetch: Task.async(function* (guidOrInfo) {
fetch: function (guidOrInfo) {
throw new Error("Not yet implemented");
}),
},
/**
* Retrieves an object representation of a bookmarked item, along with all of
* its descendants, if any.
*
* Each node in the tree is an object that extends
* the item representation described above with some additional properties:
* Each node in the tree is an object that extends the item representation
* described above with some additional properties:
*
* - [deprecated] id (number)
* the item's id. Defined only if aOptions.includeItemIds is set.
@ -227,12 +243,12 @@ let Bookmarks = Object.freeze({
* the number of items, including the root item itself, which are
* represented in the resolved object.
*
* Bookmarked URIs may also have the following properties:
* Bookmarked URLs may also have the following properties:
* - tags (string)
* csv string of the bookmark's tags, if any.
* - charset (string)
* the last known charset of the bookmark, if any.
* - iconuri (string)
* - iconurl (URL)
* the bookmark's favicon URL, if any.
*
* Folders may also have the following properties:
@ -266,12 +282,13 @@ let Bookmarks = Object.freeze({
* bookmarks tree. if guid points to a non-existent item, the
* returned promise is resolved to null.
* @rejects JavaScript exception.
* @throws if input is invalid.
*/
// XXX WIP XXX: will replace functionality for these methods:
// PlacesUtils.promiseBookmarksTree()
fetchTree: Task.async(function* (guid = "", options = {}) {
fetchTree: function (guid = "", options = {}) {
throw new Error("Not yet implemented");
}),
},
/**
* Reorders contents of a folder based on a provided array of GUIDs.
@ -286,10 +303,11 @@ let Bookmarks = Object.freeze({
*
* @return {Promise} resolved when reordering is complete.
* @rejects JavaScript exception.
* @throws if input is invalid.
*/
// XXX WIP XXX Will replace functionality from these methods:
// void setItemIndex(in long long aItemId, in long aNewIndex);
reorder: Task.async(function* (parentGuid, orderedChildrenGuids) {
reorder: function (parentGuid, orderedChildrenGuids) {
throw new Error("Not yet implemented");
})
}
});

View File

@ -117,23 +117,26 @@ treechildren.autocomplete-treebody::-moz-tree-cell-text(selected) {
color: MenuText;
}
.ac-url-box {
/* When setting a vertical margin here, half of that needs to be added
.ac-title-box's translateY for when .ac-url-box is hidden (see below). */
margin-top: 1px;
}
.autocomplete-richlistitem[actiontype="keyword"] .ac-url-box,
.autocomplete-richlistitem[actiontype="searchengine"] .ac-url-box,
.autocomplete-richlistitem[actiontype="visiturl"] .ac-url-box,
.autocomplete-richlistitem[type~="autofill"] .ac-url-box {
display: none;
visibility: hidden;
}
.autocomplete-richlistitem[actiontype="keyword"] .ac-title-box,
.autocomplete-richlistitem[actiontype="searchengine"] .ac-title-box,
.autocomplete-richlistitem[actiontype="visiturl"] .ac-title-box,
.autocomplete-richlistitem[type~="autofill"] .ac-title-box {
margin-top: 12px;
margin-bottom: 12px;
}
.ac-url-box {
margin-top: 1px;
/* Center the title by moving it down by half of .ac-url-box's height,
including vertical margins (if any). */
transform: translateY(.5em);
}
.ac-site-icon {

View File

@ -102,23 +102,26 @@ treechildren.autocomplete-treebody::-moz-tree-cell-text(selected) {
padding: 5px 2px;
}
.ac-url-box {
/* When setting a vertical margin here, half of that needs to be added
.ac-title-box's translateY for when .ac-url-box is hidden (see below). */
margin-top: 1px;
}
.autocomplete-richlistitem[actiontype="keyword"] .ac-url-box,
.autocomplete-richlistitem[actiontype="searchengine"] .ac-url-box,
.autocomplete-richlistitem[actiontype="visiturl"] .ac-url-box,
.autocomplete-richlistitem[type~="autofill"] .ac-url-box {
display: none;
visibility: hidden;
}
.autocomplete-richlistitem[actiontype="keyword"] .ac-title-box,
.autocomplete-richlistitem[actiontype="searchengine"] .ac-title-box,
.autocomplete-richlistitem[actiontype="visiturl"] .ac-title-box,
.autocomplete-richlistitem[type~="autofill"] .ac-title-box {
margin-top: 12px;
margin-bottom: 12px;
}
.ac-url-box {
margin-top: 1px;
/* Center the title by moving it down by half of .ac-url-box's height,
including vertical margins (if any). */
transform: translateY(.5em);
}
.ac-site-icon {

View File

@ -130,27 +130,30 @@ treechildren.autocomplete-treebody::-moz-tree-cell-text(selected) {
}
%endif
.ac-title-box {
margin-top: 4px;
}
.ac-url-box {
/* When setting a vertical margin here, half of that needs to be added
.ac-title-box's translateY for when .ac-url-box is hidden (see below). */
margin: 1px 0 4px;
}
.autocomplete-richlistitem[actiontype="keyword"] .ac-url-box,
.autocomplete-richlistitem[actiontype="searchengine"] .ac-url-box,
.autocomplete-richlistitem[actiontype="visiturl"] .ac-url-box,
.autocomplete-richlistitem[type~="autofill"] .ac-url-box {
display: none;
visibility: hidden;
}
.autocomplete-richlistitem[actiontype="keyword"] .ac-title-box,
.autocomplete-richlistitem[actiontype="searchengine"] .ac-title-box,
.autocomplete-richlistitem[actiontype="visiturl"] .ac-title-box,
.autocomplete-richlistitem[type~="autofill"] .ac-title-box {
margin-top: 12px;
margin-bottom: 12px;
}
.ac-title-box {
margin-top: 4px;
}
.ac-url-box {
margin: 1px 0 4px;
/* Center the title by moving it down by half of .ac-url-box's height,
including vertical margins (if any). */
transform: translateY(calc(.5em + 2px));
}
.ac-site-icon {