summaryrefslogtreecommitdiffstats
path: root/toolkit/jetpack/sdk/context-menu/context.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/jetpack/sdk/context-menu/context.js')
-rw-r--r--toolkit/jetpack/sdk/context-menu/context.js147
1 files changed, 147 insertions, 0 deletions
diff --git a/toolkit/jetpack/sdk/context-menu/context.js b/toolkit/jetpack/sdk/context-menu/context.js
new file mode 100644
index 000000000..fc5aea500
--- /dev/null
+++ b/toolkit/jetpack/sdk/context-menu/context.js
@@ -0,0 +1,147 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+const { Class } = require("../core/heritage");
+const { extend } = require("../util/object");
+const { MatchPattern } = require("../util/match-pattern");
+const readers = require("./readers");
+
+// Context class is required to implement a single `isCurrent(target)` method
+// that must return boolean value indicating weather given target matches a
+// context or not. Most context implementations below will have an associated
+// reader that way context implementation can setup a reader to extract necessary
+// information to make decision if target is matching a context.
+const Context = Class({
+ isRequired: false,
+ isCurrent(target) {
+ throw Error("Context class must implement isCurrent(target) method");
+ },
+ get required() {
+ Object.defineProperty(this, "required", {
+ value: Object.assign(Object.create(Object.getPrototypeOf(this)),
+ this,
+ {isRequired: true})
+ });
+ return this.required;
+ }
+});
+Context.required = function(...params) {
+ return Object.assign(new this(...params), {isRequired: true});
+};
+exports.Context = Context;
+
+
+// Next few context implementations use an associated reader to extract info
+// from the context target and story it to a private symbol associtaed with
+// a context implementation. That way name collisions are avoided while required
+// information is still carried along.
+const isPage = Symbol("context/page?")
+const PageContext = Class({
+ extends: Context,
+ read: {[isPage]: new readers.isPage()},
+ isCurrent: target => target[isPage]
+});
+exports.Page = PageContext;
+
+const isFrame = Symbol("context/frame?");
+const FrameContext = Class({
+ extends: Context,
+ read: {[isFrame]: new readers.isFrame()},
+ isCurrent: target => target[isFrame]
+});
+exports.Frame = FrameContext;
+
+const selection = Symbol("context/selection")
+const SelectionContext = Class({
+ read: {[selection]: new readers.Selection()},
+ isCurrent: target => !!target[selection]
+});
+exports.Selection = SelectionContext;
+
+const link = Symbol("context/link");
+const LinkContext = Class({
+ extends: Context,
+ read: {[link]: new readers.LinkURL()},
+ isCurrent: target => !!target[link]
+});
+exports.Link = LinkContext;
+
+const isEditable = Symbol("context/editable?")
+const EditableContext = Class({
+ extends: Context,
+ read: {[isEditable]: new readers.isEditable()},
+ isCurrent: target => target[isEditable]
+});
+exports.Editable = EditableContext;
+
+
+const mediaType = Symbol("context/mediaType")
+
+const ImageContext = Class({
+ extends: Context,
+ read: {[mediaType]: new readers.MediaType()},
+ isCurrent: target => target[mediaType] === "image"
+});
+exports.Image = ImageContext;
+
+
+const VideoContext = Class({
+ extends: Context,
+ read: {[mediaType]: new readers.MediaType()},
+ isCurrent: target => target[mediaType] === "video"
+});
+exports.Video = VideoContext;
+
+
+const AudioContext = Class({
+ extends: Context,
+ read: {[mediaType]: new readers.MediaType()},
+ isCurrent: target => target[mediaType] === "audio"
+});
+exports.Audio = AudioContext;
+
+const isSelectorMatch = Symbol("context/selector/mathches?")
+const SelectorContext = Class({
+ extends: Context,
+ initialize(selector) {
+ this.selector = selector;
+ // Each instance of selector context will need to store read
+ // data into different field, so that case with multilpe selector
+ // contexts won't cause a conflicts.
+ this[isSelectorMatch] = Symbol(selector);
+ this.read = {[this[isSelectorMatch]]: new readers.SelectorMatch(selector)};
+ },
+ isCurrent(target) {
+ return target[this[isSelectorMatch]];
+ }
+});
+exports.Selector = SelectorContext;
+
+const url = Symbol("context/url");
+const URLContext = Class({
+ extends: Context,
+ initialize(pattern) {
+ this.pattern = new MatchPattern(pattern);
+ },
+ read: {[url]: new readers.PageURL()},
+ isCurrent(target) {
+ return this.pattern.test(target[url]);
+ }
+});
+exports.URL = URLContext;
+
+var PredicateContext = Class({
+ extends: Context,
+ initialize(isMatch) {
+ if (typeof(isMatch) !== "function") {
+ throw TypeError("Predicate context mus be passed a function");
+ }
+
+ this.isMatch = isMatch
+ },
+ isCurrent(target) {
+ return this.isMatch(target);
+ }
+});
+exports.Predicate = PredicateContext;