You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
3.2 KiB
96 lines
3.2 KiB
import { copyObj, createObj } from "./util/misc.js" |
|
|
|
// Known modes, by name and by MIME |
|
export let modes = {}, mimeModes = {} |
|
|
|
// Extra arguments are stored as the mode's dependencies, which is |
|
// used by (legacy) mechanisms like loadmode.js to automatically |
|
// load a mode. (Preferred mechanism is the require/define calls.) |
|
export function defineMode(name, mode) { |
|
if (arguments.length > 2) |
|
mode.dependencies = Array.prototype.slice.call(arguments, 2) |
|
modes[name] = mode |
|
} |
|
|
|
export function defineMIME(mime, spec) { |
|
mimeModes[mime] = spec |
|
} |
|
|
|
// Given a MIME type, a {name, ...options} config object, or a name |
|
// string, return a mode config object. |
|
export function resolveMode(spec) { |
|
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { |
|
spec = mimeModes[spec] |
|
} else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { |
|
let found = mimeModes[spec.name] |
|
if (typeof found == "string") found = {name: found} |
|
spec = createObj(found, spec) |
|
spec.name = found.name |
|
} else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { |
|
return resolveMode("application/xml") |
|
} else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) { |
|
return resolveMode("application/json") |
|
} |
|
if (typeof spec == "string") return {name: spec} |
|
else return spec || {name: "null"} |
|
} |
|
|
|
// Given a mode spec (anything that resolveMode accepts), find and |
|
// initialize an actual mode object. |
|
export function getMode(options, spec) { |
|
spec = resolveMode(spec) |
|
let mfactory = modes[spec.name] |
|
if (!mfactory) return getMode(options, "text/plain") |
|
let modeObj = mfactory(options, spec) |
|
if (modeExtensions.hasOwnProperty(spec.name)) { |
|
let exts = modeExtensions[spec.name] |
|
for (let prop in exts) { |
|
if (!exts.hasOwnProperty(prop)) continue |
|
if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop] |
|
modeObj[prop] = exts[prop] |
|
} |
|
} |
|
modeObj.name = spec.name |
|
if (spec.helperType) modeObj.helperType = spec.helperType |
|
if (spec.modeProps) for (let prop in spec.modeProps) |
|
modeObj[prop] = spec.modeProps[prop] |
|
|
|
return modeObj |
|
} |
|
|
|
// This can be used to attach properties to mode objects from |
|
// outside the actual mode definition. |
|
export let modeExtensions = {} |
|
export function extendMode(mode, properties) { |
|
let exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}) |
|
copyObj(properties, exts) |
|
} |
|
|
|
export function copyState(mode, state) { |
|
if (state === true) return state |
|
if (mode.copyState) return mode.copyState(state) |
|
let nstate = {} |
|
for (let n in state) { |
|
let val = state[n] |
|
if (val instanceof Array) val = val.concat([]) |
|
nstate[n] = val |
|
} |
|
return nstate |
|
} |
|
|
|
// Given a mode and a state (for that mode), find the inner mode and |
|
// state at the position that the state refers to. |
|
export function innerMode(mode, state) { |
|
let info |
|
while (mode.innerMode) { |
|
info = mode.innerMode(state) |
|
if (!info || info.mode == mode) break |
|
state = info.state |
|
mode = info.mode |
|
} |
|
return info || {mode: mode, state: state} |
|
} |
|
|
|
export function startState(mode, a1, a2) { |
|
return mode.startState ? mode.startState(a1, a2) : true |
|
}
|
|
|