'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

const core = require('./core-88c2738f.js');
require('./_commonjsHelpers-72d386ba.js');
const version = require('./version-b9637fae.js');
const index = require('./index-2cc75506.js');

/**
 * Performs a deep comparison between two values to determine if they are
 * equivalent.
 *
 * **Note:** This method supports comparing arrays, array buffers, booleans,
 * date objects, error objects, maps, numbers, `Object` objects, regexes,
 * sets, strings, symbols, and typed arrays. `Object` objects are compared
 * by their own, not inherited, enumerable properties. Functions and DOM
 * nodes are compared by strict equality, i.e. `===`.
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to compare.
 * @param {*} other The other value to compare.
 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
 * @example
 *
 * var object = { 'a': 1 };
 * var other = { 'a': 1 };
 *
 * _.isEqual(object, other);
 * // => true
 *
 * object === other;
 * // => false
 */
function isEqual(value, other) {
  return version.baseIsEqual(value, other);
}

var isEqual_1 = isEqual;

/** `Object#toString` result references. */
var mapTag = '[object Map]',
    setTag = '[object Set]';

/** Used for built-in method references. */
var objectProto = Object.prototype;

/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;

/**
 * Checks if `value` is an empty object, collection, map, or set.
 *
 * Objects are considered empty if they have no own enumerable string keyed
 * properties.
 *
 * Array-like values such as `arguments` objects, arrays, buffers, strings, or
 * jQuery-like collections are considered empty if they have a `length` of `0`.
 * Similarly, maps and sets are considered empty if they have a `size` of `0`.
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is empty, else `false`.
 * @example
 *
 * _.isEmpty(null);
 * // => true
 *
 * _.isEmpty(true);
 * // => true
 *
 * _.isEmpty(1);
 * // => true
 *
 * _.isEmpty([1, 2, 3]);
 * // => false
 *
 * _.isEmpty({ 'a': 1 });
 * // => false
 */
function isEmpty(value) {
  if (value == null) {
    return true;
  }
  if (version.isArrayLike(value) &&
      (version.isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||
        version.isBuffer(value) || version.isTypedArray(value) || version.isArguments(value))) {
    return !value.length;
  }
  var tag = version.getTag(value);
  if (tag == mapTag || tag == setTag) {
    return !value.size;
  }
  if (version.isPrototype(value)) {
    return !version.baseKeys(value).length;
  }
  for (var key in value) {
    if (hasOwnProperty.call(value, key)) {
      return false;
    }
  }
  return true;
}

var isEmpty_1 = isEmpty;

/* Built-in method references for those with the same name as other `lodash` methods. */
var nativeCeil = Math.ceil,
    nativeMax = Math.max;

/**
 * The base implementation of `_.range` and `_.rangeRight` which doesn't
 * coerce arguments.
 *
 * @private
 * @param {number} start The start of the range.
 * @param {number} end The end of the range.
 * @param {number} step The value to increment or decrement by.
 * @param {boolean} [fromRight] Specify iterating from right to left.
 * @returns {Array} Returns the range of numbers.
 */
function baseRange(start, end, step, fromRight) {
  var index = -1,
      length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
      result = Array(length);

  while (length--) {
    result[fromRight ? length : ++index] = start;
    start += step;
  }
  return result;
}

var _baseRange = baseRange;

/**
 * Checks if the given arguments are from an iteratee call.
 *
 * @private
 * @param {*} value The potential iteratee value argument.
 * @param {*} index The potential iteratee index or key argument.
 * @param {*} object The potential iteratee object argument.
 * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
 *  else `false`.
 */
function isIterateeCall(value, index, object) {
  if (!version.isObject(object)) {
    return false;
  }
  var type = typeof index;
  if (type == 'number'
        ? (version.isArrayLike(object) && version.isIndex(index, object.length))
        : (type == 'string' && index in object)
      ) {
    return version.eq(object[index], value);
  }
  return false;
}

var _isIterateeCall = isIterateeCall;

/** Used to match a single whitespace character. */
var reWhitespace = /\s/;

/**
 * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
 * character of `string`.
 *
 * @private
 * @param {string} string The string to inspect.
 * @returns {number} Returns the index of the last non-whitespace character.
 */
function trimmedEndIndex(string) {
  var index = string.length;

  while (index-- && reWhitespace.test(string.charAt(index))) {}
  return index;
}

var _trimmedEndIndex = trimmedEndIndex;

/** Used to match leading whitespace. */
var reTrimStart = /^\s+/;

/**
 * The base implementation of `_.trim`.
 *
 * @private
 * @param {string} string The string to trim.
 * @returns {string} Returns the trimmed string.
 */
function baseTrim(string) {
  return string
    ? string.slice(0, _trimmedEndIndex(string) + 1).replace(reTrimStart, '')
    : string;
}

var _baseTrim = baseTrim;

/** Used as references for various `Number` constants. */
var NAN = 0 / 0;

/** Used to detect bad signed hexadecimal string values. */
var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;

/** Used to detect binary string values. */
var reIsBinary = /^0b[01]+$/i;

/** Used to detect octal string values. */
var reIsOctal = /^0o[0-7]+$/i;

/** Built-in method references without a dependency on `root`. */
var freeParseInt = parseInt;

/**
 * Converts `value` to a number.
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Lang
 * @param {*} value The value to process.
 * @returns {number} Returns the number.
 * @example
 *
 * _.toNumber(3.2);
 * // => 3.2
 *
 * _.toNumber(Number.MIN_VALUE);
 * // => 5e-324
 *
 * _.toNumber(Infinity);
 * // => Infinity
 *
 * _.toNumber('3.2');
 * // => 3.2
 */
function toNumber(value) {
  if (typeof value == 'number') {
    return value;
  }
  if (version.isSymbol(value)) {
    return NAN;
  }
  if (version.isObject(value)) {
    var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
    value = version.isObject(other) ? (other + '') : other;
  }
  if (typeof value != 'string') {
    return value === 0 ? value : +value;
  }
  value = _baseTrim(value);
  var isBinary = reIsBinary.test(value);
  return (isBinary || reIsOctal.test(value))
    ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
    : (reIsBadHex.test(value) ? NAN : +value);
}

var toNumber_1 = toNumber;

/** Used as references for various `Number` constants. */
var INFINITY = 1 / 0,
    MAX_INTEGER = 1.7976931348623157e+308;

/**
 * Converts `value` to a finite number.
 *
 * @static
 * @memberOf _
 * @since 4.12.0
 * @category Lang
 * @param {*} value The value to convert.
 * @returns {number} Returns the converted number.
 * @example
 *
 * _.toFinite(3.2);
 * // => 3.2
 *
 * _.toFinite(Number.MIN_VALUE);
 * // => 5e-324
 *
 * _.toFinite(Infinity);
 * // => 1.7976931348623157e+308
 *
 * _.toFinite('3.2');
 * // => 3.2
 */
function toFinite(value) {
  if (!value) {
    return value === 0 ? value : 0;
  }
  value = toNumber_1(value);
  if (value === INFINITY || value === -INFINITY) {
    var sign = (value < 0 ? -1 : 1);
    return sign * MAX_INTEGER;
  }
  return value === value ? value : 0;
}

var toFinite_1 = toFinite;

/**
 * Creates a `_.range` or `_.rangeRight` function.
 *
 * @private
 * @param {boolean} [fromRight] Specify iterating from right to left.
 * @returns {Function} Returns the new range function.
 */
function createRange(fromRight) {
  return function(start, end, step) {
    if (step && typeof step != 'number' && _isIterateeCall(start, end, step)) {
      end = step = undefined;
    }
    // Ensure the sign of `-0` is preserved.
    start = toFinite_1(start);
    if (end === undefined) {
      end = start;
      start = 0;
    } else {
      end = toFinite_1(end);
    }
    step = step === undefined ? (start < end ? 1 : -1) : toFinite_1(step);
    return _baseRange(start, end, step, fromRight);
  };
}

var _createRange = createRange;

/**
 * Creates an array of numbers (positive and/or negative) progressing from
 * `start` up to, but not including, `end`. A step of `-1` is used if a negative
 * `start` is specified without an `end` or `step`. If `end` is not specified,
 * it's set to `start` with `start` then set to `0`.
 *
 * **Note:** JavaScript follows the IEEE-754 standard for resolving
 * floating-point values which can produce unexpected results.
 *
 * @static
 * @since 0.1.0
 * @memberOf _
 * @category Util
 * @param {number} [start=0] The start of the range.
 * @param {number} end The end of the range.
 * @param {number} [step=1] The value to increment or decrement by.
 * @returns {Array} Returns the range of numbers.
 * @see _.inRange, _.rangeRight
 * @example
 *
 * _.range(4);
 * // => [0, 1, 2, 3]
 *
 * _.range(-4);
 * // => [0, -1, -2, -3]
 *
 * _.range(1, 5);
 * // => [1, 2, 3, 4]
 *
 * _.range(0, 20, 5);
 * // => [0, 5, 10, 15]
 *
 * _.range(0, -4, -1);
 * // => [0, -1, -2, -3]
 *
 * _.range(1, 4, 0);
 * // => [1, 1, 1]
 *
 * _.range(0);
 * // => []
 */
var range = _createRange();

var range_1 = range;

class DataURLImageSupport {
    insert(file, done, progressFn) {
        const reader = new FileReader();
        reader.onload = () => {
            const dataURL = reader.result;
            setTimeout(() => {
                done(null, dataURL.toString());
            }, 2000);
        };
        let progress = 0;
        progressFn(progress, 0, 100);
        range_1(1, 100).forEach(n => {
            setTimeout(() => {
                progressFn(n, n, 100);
            }, n * 20);
        });
        // if external asset support .. add reader.readAsArrayBuffer ..
        reader.readAsDataURL(file);
    }
    delete(src, done) {
        done();
    }
}

class DataURLUploadSoundSupport {
    insert(file, done, progressFn) {
        const reader = new FileReader();
        reader.onload = () => {
            const dataURL = reader.result;
            setTimeout(() => {
                done(null, dataURL.toString());
            }, 2000);
        };
        let progress = 0;
        progressFn(progress, 0, 100);
        range_1(1, 100).forEach(n => {
            setTimeout(() => {
                progressFn(n, n, 100);
            }, n * 20);
        });
        // if external asset support .. add reader.readAsArrayBuffer ..
        reader.readAsDataURL(file);
    }
    delete(src, done) {
        done();
    }
}

const Author = class {
    constructor(hostRef) {
        core.registerInstance(this, hostRef);
        this._modelLoadedState = false;
        /**
         * Allows disabling of the default behaviour which is to look up and load the JS bundle that define the Custom Elements
         * used by the item config.
         * This if for advanced use cases when using the pie-player in a container that is managing loading of Custom Elements and Controllers.
         */
        this.disableBundler = false;
        /**
         * Adds a preview view which will render the content in another tab as it may appear to a student or instructor.
         */
        this.addPreview = false;
        this.elementsLoaded = false;
        /**
         * If pie-author is used inside pie-api-author component. Do not set it manually.
         */
        this.isInsidePieApiAuthor = false;
        this.pieLoader = new version.PieLoader();
        this.fileInput = null;
        this.imageHandler = null;
        /** external providers can set this if they need to upload the assets to the cloud etc. by default we use data urls */
        this.imageSupport = new DataURLImageSupport();
        /** external providers can set this if they need to upload the assets to the cloud etc. by default we use data urls */
        this.uploadSoundSupport = new DataURLUploadSoundSupport();
        this.version = version.VERSION;
        /**
         * used in our demo environment to allow author to watch config settings and make updates
         * defaults to false (do not set it to true because it was not tested properly)
         * @type {boolean}
         * @private
         */
        this.canWatchConfigSettings = false;
        this.isAdvancedItemConfig = (config) => config.pie;
        this.getPieContentModelWithToggledComplexRubric = async ({ complexRubricCheckedValues, pieContentModel }) => {
            const { shouldAddComplexRubric, shouldRemoveComplexRubric, complexRubricElements } = complexRubricCheckedValues || {};
            if (shouldAddComplexRubric) {
                // we add complex-rubric to config
                return this.addComplexRubric(version.cloneDeep(pieContentModel));
            }
            if (shouldRemoveComplexRubric) {
                // we remove complex-rubric from config
                return this.removeComplexRubricItemTypes(version.cloneDeep(pieContentModel), complexRubricElements);
            }
            return null;
        };
        this.getNewConfig = (newConfig) => {
            if (this.isAdvancedItemConfig(this.config)) {
                return Object.assign(Object.assign({}, this.config), { pie: newConfig });
            }
            return newConfig;
        };
        this.setModelsAndConfigurations = () => {
            if (this.pieContentModel && this.pieContentModel.models) {
                this.pieContentModel.models.map(model => {
                    let pieEl = this.el.querySelector(`[id='${model.id}']`);
                    !pieEl && (pieEl = this.el.querySelector(`[pie-id='${model.id}']`));
                    if (pieEl) {
                        const pieElName = pieEl.tagName.toLowerCase().split("-config")[0];
                        try {
                            const packageName = version.parseNpm(this.pieContentModel.elements[pieElName]).name;
                            pieEl.model = model;
                            if (this.configSettings && this.configSettings[packageName]) {
                                pieEl.configuration = this.configSettings[packageName];
                            }
                        }
                        catch (e) {
                            console.log(e.toString(), pieElName, this.pieContentModel.elements[pieElName]);
                        }
                    }
                });
            }
        };
        this.handleFileInputChange = (e) => {
            const input = e.target;
            if (!this.imageHandler) {
                console.error("no image handler - but file input change triggered?");
                return;
            }
            const files = input.files;
            if (files.length < 1 || !files[0]) {
                this.imageHandler.cancel();
                this.imageHandler = null;
            }
            else {
                const file = files[0];
                this.imageHandler.fileChosen(file);
                this.fileInput.value = "";
                this.insertImage(file);
            }
        };
        this.handleInsertImage = (e) => {
            console.log("[handleInsertImage]", e);
            this.imageHandler = e.detail;
            if (!e.detail.isPasted) {
                this.fileInput.click();
            }
            else if (e.detail.getChosenFile) {
                // this is for images that were pasted into the editor (or dropped)
                // they also need to be uploaded, but the file input doesn't have to be used
                try {
                    const file = e.detail.getChosenFile();
                    if (file) {
                        this.insertImage(file);
                    }
                }
                catch (e) {
                    console.error(e);
                }
            }
        };
        this.handleDeleteImage = (e) => {
            console.log("[handleDeleteImage ..]", e);
            this.imageSupport.delete(e.detail.src, e.detail.done);
        };
        this.handleInsertSound = (e) => {
            console.log("[handleInsertSound]", e);
            this.uploadSoundSupport.insert(e.detail.fileChosen, e.detail.done);
        };
        this.handleDeleteSound = (e) => {
            console.log("[handleDeleteSound ..]", e);
            this.uploadSoundSupport.delete(e.detail.src, e.detail.done);
        };
        this.modelUpdated = core.createEvent(this, "modelUpdated", 7);
        this.modelLoaded = core.createEvent(this, "modelLoaded", 7);
        this.doc = core.getContext(this, "document");
    }
    async validateModels() {
        if (!this.pieContentModel || !this.pieContentModel.models) {
            console.error('No pie content model');
            return { hasErrors: false, validatedModels: {} };
        }
        return (this.pieContentModel.models || []).reduce((acc, model) => {
            let pieEl = this.el.querySelector(`[id='${model.id}']`);
            !pieEl && (pieEl = this.el.querySelector(`[pie-id='${model.id}']`));
            if (pieEl) {
                const pieElName = pieEl.tagName.toLowerCase().split("-config")[0];
                const controller = this.pieLoader.getController(pieElName);
                const packageName = version.parseNpm(this.pieContentModel.elements[pieElName]).name;
                const configuration = this.configSettings && this.configSettings[packageName] || {};
                if (controller && controller.validate) {
                    // here we call controller.validate which returns an object with all the errors
                    const errors = controller.validate(model, configuration);
                    // here we can update the model in author, so we can set errors
                    pieEl.model = Object.assign(Object.assign({}, model), { errors });
                    // for ebsr
                    if (errors && errors.partA && errors.partB) {
                        acc.hasErrors = acc.hasErrors || (!isEmpty_1(errors.partA) || !isEmpty_1(errors.partB));
                    }
                    else {
                        // here we return a boolean value if models are valid or not
                        acc.hasErrors = acc.hasErrors || !isEmpty_1(errors);
                    }
                    acc.validatedModels = Object.assign(Object.assign({}, acc.validatedModels), { [model.id]: Object.assign(Object.assign({}, model), { errors }) });
                }
                else {
                    acc.validatedModels = Object.assign(Object.assign({}, acc.validatedModels), { [model.id]: model });
                }
            }
            return acc;
        }, { hasErrors: false, validatedModels: {} });
    }
    insertImage(file) {
        this.imageSupport.insert(file, (e, src) => {
            if (e) {
                console.warn("error inserting image: ", e.message);
                console.error(e);
            }
            this.imageHandler.done(e, src);
            this.imageHandler = null;
        }, (percent, bytes, total) => this.imageHandler.progress(percent, bytes, total));
    }
    getRenderMarkup() {
        let markup = this.pieContentModel ? this.pieContentModel.markup : "";
        if (markup) {
            Object.keys(this.pieContentModel.elements).forEach(key => {
                markup = markup.split(key).join(key + "-config");
            });
            return markup;
        }
    }
    async watchConfig(newValue, oldValue) {
        if (newValue && !isEqual_1(newValue, oldValue)) {
            try {
                this.elementsLoaded = false;
                this._modelLoadedState = false;
                const pieContentModel = version.pieContentFromConfig(newValue);
                const complexRubricCheckedValues = version.complexRubricChecks(pieContentModel, this.configSettings);
                const { shouldAddComplexRubric, shouldRemoveComplexRubric } = complexRubricCheckedValues || {};
                // if changes are needed
                if (shouldAddComplexRubric || shouldRemoveComplexRubric) {
                    this.pieContentModel = null;
                    const newConfig = await this.getPieContentModelWithToggledComplexRubric({
                        complexRubricCheckedValues,
                        pieContentModel
                    });
                    // and then we reset the config
                    if (newConfig) {
                        this.config = this.getNewConfig(newConfig);
                    }
                }
                else {
                    // if there's no change needed, we can proceed with updating the config and loading pie-elements
                    this.pieContentModel = pieContentModel;
                    this.addConfigTags(this.pieContentModel);
                    await this.loadPieElements();
                }
            }
            catch (error) {
                console.log(`ERROR ${error}`);
            }
        }
    }
    async removeComplexRubricItemTypes(pieContentModel, rubricElements) {
        if (!rubricElements.length || !pieContentModel.models) {
            return pieContentModel;
        }
        // delete the complex-rubric elements from elements object
        rubricElements.forEach(rubricElementKey => delete pieContentModel.elements[rubricElementKey]);
        const { markupWithoutComplexRubric, deletedComplexRubricItemIds } = version.removeComplexRubricFromMarkup(pieContentModel, rubricElements, this.doc);
        // delete the complex-rubric nodes from markup
        pieContentModel.markup = markupWithoutComplexRubric;
        // delete the complex-rubric models
        pieContentModel.models = pieContentModel.models.filter(model => !deletedComplexRubricItemIds.includes(model.id));
        return pieContentModel;
    }
    async addComplexRubric(pieContentModel) {
        const complexRubricModel = Object.assign({ id: version.COMPLEX_RUBRIC, element: `pie-${version.COMPLEX_RUBRIC}` }, this.defaultComplexRubricModel || {});
        const packageName = `@pie-element/${version.COMPLEX_RUBRIC}`;
        // add complex-rubric in elements, IF it isn't there already
        let content = version.addPackageToContent(pieContentModel, packageName, complexRubricModel);
        // but if complex-rubric is already in elements, then just add it in the models
        if (!content) {
            content = version.addModelToContent(pieContentModel, version.createTag(packageName), complexRubricModel);
        }
        return version.addComplexRubric(content);
    }
    addConfigTags(c) {
        if (!c.markup && c.models) {
            const tags = c.models.map(model => {
                return `<${model.element}-config id="${model.id}"></${model.element}-config>`;
            });
            c.markup = tags.join("");
        }
    }
    async watchElementsLoaded(newValue, oldValue) {
        if (newValue && !oldValue) {
            await this.updateModels();
        }
    }
    async updateModels() {
        if (this.pieContentModel &&
            this.pieContentModel.elements &&
            this.pieContentModel.markup) {
            if (!this.pieContentModel.models) {
                this.pieContentModel.models = [];
            }
            const tempDiv = this.doc.createElement("div");
            tempDiv.innerHTML = this.pieContentModel.markup;
            const elsWithId = tempDiv.querySelectorAll("[id]");
            // set up a model for each pie defined in the markup
            elsWithId.forEach(el => {
                const pieElName = el.tagName.toLowerCase().split("-config")[0];
                // initialize emtpy model if this is a pie
                if (this.pieContentModel.elements[pieElName]) {
                    const elementId = el.getAttribute("id");
                    if (!this.pieContentModel.models.find(m => m.id === elementId)) {
                        const model = { id: elementId, element: pieElName };
                        this.pieContentModel.models.push(model);
                    }
                }
            });
            tempDiv.remove();
        }
        if (this.pieContentModel && this.pieContentModel.models) {
            this.setModelsAndConfigurations();
            if (this._modelLoadedState === false) {
                this._modelLoadedState = true;
                this.modelLoaded.emit(this.pieContentModel);
            }
        }
    }
    watchConfigSettings() {
        if (this.canWatchConfigSettings) {
            this.setModelsAndConfigurations();
        }
    }
    componentDidUnload() {
        this.el.removeEventListener(index.lib_3.TYPE, this.handleInsertImage);
        this.el.removeEventListener(index.lib_2.TYPE, this.handleDeleteImage);
        this.el.removeEventListener(index.lib_5.TYPE, this.handleInsertSound);
        this.el.removeEventListener(index.lib_4.TYPE, this.handleDeleteSound);
        if (this.fileInput) {
            this.fileInput.removeEventListener("change", this.handleFileInputChange);
        }
    }
    async componentWillLoad() {
        if (this.config) {
            this.watchConfig(this.config, {});
        }
        // Note: cannot use the @Listen decorator as creates bundling problems due
        // to `.` in event name.
        this.el.addEventListener(index.lib_1.TYPE, async (e) => {
            // set the internal model
            // emit a content-item level event with the model
            let rubricChanged;
            if (this.pieContentModel && e.update) {
                this.pieContentModel.models.forEach(m => {
                    if (m.id === e.update.id && m.element === e.update.element) {
                        rubricChanged = rubricChanged || m.rubricEnabled !== e.update.rubricEnabled;
                        Object.assign(m, e.update);
                        if (e.update.errors && !isEmpty_1(e.update.errors)) {
                            this.validateModels();
                        }
                    }
                });
            }
            if (this._modelLoadedState) {
                if (rubricChanged) {
                    if (this.isInsidePieApiAuthor) {
                        // if pie-author is used inside pie-api-author, then what we need is to
                        // calculate the new pieContentModel and make sure we emit the modelUpdated event with the updated pieContentModel
                        // first thing, we check what changed (if we have to add or remove complex-rubric)
                        const complexRubricCheckedValues = version.complexRubricChecks(this.pieContentModel, this.configSettings);
                        const { shouldAddComplexRubric, shouldRemoveComplexRubric } = complexRubricCheckedValues || {};
                        if (shouldAddComplexRubric || shouldRemoveComplexRubric) {
                            // then, if changes are needed, we make them and save the new contentModel
                            const newPieContentModel = await this.getPieContentModelWithToggledComplexRubric({
                                complexRubricCheckedValues,
                                pieContentModel: this.pieContentModel
                            });
                            // last thing to do is to make sure we send the updated pie content model to pie-api-author
                            // (which listens for this event) who will trigger watchConfig
                            if (newPieContentModel) {
                                this.modelUpdated.emit(newPieContentModel);
                            }
                        }
                    }
                    else {
                        // however, if we only use pie-player-components, just force the call to watchConfig
                        await this.watchConfig(this.config, {});
                    }
                }
                else {
                    // if rubricEnabled did not change, just behave as previously
                    // (pie-api-author listens for this event and triggers watchConfig)
                    this.modelUpdated.emit(this.pieContentModel);
                }
            }
        });
        this.el.addEventListener(index.lib_3.TYPE, this.handleInsertImage);
        this.el.addEventListener(index.lib_2.TYPE, this.handleDeleteImage);
        this.el.addEventListener(index.lib_5.TYPE, this.handleInsertSound);
        this.el.addEventListener(index.lib_4.TYPE, this.handleDeleteSound);
    }
    async componentDidLoad() {
        await this.afterRender();
    }
    async componentDidUpdate() {
        await this.afterRender();
        if (this.fileInput) {
            this.fileInput.addEventListener("change", this.handleFileInputChange);
        }
    }
    async loadPieElements() {
        if (this.config && !this.disableBundler) {
            let endpoints = version.DEFAULT_ENDPOINTS.prod;
            if (this.bundleHost &&
                ["dev", "stage", "prod"].includes(this.bundleHost)) {
                endpoints = version.DEFAULT_ENDPOINTS[this.bundleHost];
            }
            if (this.bundleEndpoints) {
                endpoints = this.bundleEndpoints;
            }
            await this.pieLoader.loadCloudPies({
                content: this.pieContentModel,
                doc: this.doc,
                endpoints,
                useCdn: false
            });
        }
    }
    renderMath() {
        setTimeout(() => {
            version.renderMath(this.el);
        }, 50);
    }
    async afterRender() {
        if (this.pieContentModel &&
            this.pieContentModel.markup &&
            !this.elementsLoaded) {
            const elements = Object.keys(this.pieContentModel.elements).map(el => ({
                name: el,
                tag: `${el}-config`
            }));
            const loadedInfo = await this.pieLoader.elementsHaveLoaded(elements);
            if (loadedInfo.val &&
                !!loadedInfo.elements.find(el => this.pieContentModel.elements[el.name])) {
                this.elementsLoaded = true;
                this.renderMath();
            }
        }
    }
    /**
     * Utility method to add a `@pie-element/rubric` section to an item config when creating an item should be used before setting the config.
     *
     * @deprecated this method is for temporary use, will be removed at next major release
     *
     * @param config the item config to mutate
     * @param rubricModel
     */
    async addRubricToConfig(config, rubricModel) {
        console.warn('If you are using complex-rubric, stop using this function to prevent having duplicated rubrics.');
        if (!rubricModel) {
            rubricModel = {
                id: "rubric",
                element: "pie-rubric",
                points: ["", "", "", ""],
                maxPoints: 4,
                excludeZero: false
            };
        }
        const configPieContent = version.pieContentFromConfig(config);
        version.addPackageToContent(configPieContent, "@pie-element/rubric", rubricModel);
        return version.addRubric(configPieContent);
    }
    /**
     * Utility method to add a `@pie-element/multi-trait-rubric` section to an item config when creating an item should be used before setting the config.
     **
     * @param config the item config to mutate
     * @param multiTraitRubricModel
     */
    async addMultiTraitRubricToConfig(config, multiTraitRubricModel) {
        console.warn('If you are using complex-rubric, stop using this function to prevent having duplicated rubrics.');
        if (!multiTraitRubricModel) {
            multiTraitRubricModel = {
                id: "multi-trait-rubric",
                element: "pie-multi-trait-rubric",
                visibleToStudent: true,
                halfScoring: false,
                excludeZero: true,
                pointLabels: true,
                description: false,
                standards: false,
                scales: [
                    {
                        maxPoints: 4,
                        scorePointsLabels: ['', '', '', ''],
                        traitLabel: 'Trait',
                        traits: [
                            {
                                name: '',
                                standards: [],
                                description: '',
                                scorePointsDescriptors: [
                                    '',
                                    '',
                                    '',
                                    '',
                                    '',
                                ],
                            },
                        ]
                    }
                ]
            };
        }
        const configPieContent = version.pieContentFromConfig(config);
        version.addPackageToContent(configPieContent, "@pie-element/multi-trait-rubric", multiTraitRubricModel);
        return version.addMultiTraitRubric(configPieContent);
    }
    render() {
        if (this.pieContentModel && this.pieContentModel.markup) {
            const markup = this.getRenderMarkup();
            if (this.addPreview) {
                return (core.h("pie-preview-layout", { config: this.config }, core.h("div", { slot: "configure" }, core.h("pie-spinner", { active: !this.elementsLoaded }, core.h("div", { class: 'author-container', innerHTML: markup }))), core.h("input", { type: "file", hidden: true, ref: r => (this.fileInput = r), style: { display: 'none' } })));
            }
            else {
                return (core.h("pie-spinner", { active: !this.elementsLoaded }, core.h("div", { class: 'author-container', innerHTML: markup }), core.h("input", { type: "file", hidden: true, ref: r => (this.fileInput = r), style: { display: 'none' } })));
            }
        }
        else {
            return core.h("pie-spinner", null);
        }
    }
    get el() { return core.getElement(this); }
    static get watchers() { return {
        "config": ["watchConfig"],
        "elementsLoaded": ["watchElementsLoaded"],
        "configSettings": ["watchConfigSettings"]
    }; }
    static get style() { return ".pie-loading{position:absolute;height:100%;width:100%;background-color:#fff;bottom:0;left:0;right:0;top:0;z-index:9999;opacity:.4}.pie-loading.fixed{position:fixed}.pie-loading:before{-webkit-box-shadow:0 0 35px rgba(63,81,181,.9);box-shadow:0 0 35px rgba(63,81,181,.9);width:50px;height:50px;-moz-animation:spinPulse 1s infinite ease-in-out;-webkit-animation:spinPulse 1s linear infinite;margin:-25px 0 0 -25px}.pie-loading:after,.pie-loading:before{content:\"\";background-color:transparent;border:5px solid rgba(63,81,181,.9);opacity:.9;border-right:5px solid transparent;border-left:5px solid transparent;border-radius:50px;position:absolute;top:50%;left:50%}.pie-loading:after{-webkit-box-shadow:0 0 15px rgba(63,81,181,.9);box-shadow:0 0 15px rgba(63,81,181,.9);width:30px;height:30px;-moz-animation:spinoffPulse 1s infinite linear;-webkit-animation:spinoffPulse 1s linear infinite;margin:-15px 0 0 -15px}\@-webkit-keyframes spinPulse{0%{-webkit-transform:rotate(160deg);transform:rotate(160deg);opacity:0;-webkit-box-shadow:0 0 1px rgba(63,81,181,.9);box-shadow:0 0 1px rgba(63,81,181,.9)}50%{-webkit-transform:rotate(145deg);transform:rotate(145deg);opacity:1}to{-webkit-transform:rotate(-320deg);transform:rotate(-320deg);opacity:0}}\@keyframes spinPulse{0%{-webkit-transform:rotate(160deg);transform:rotate(160deg);opacity:0;-webkit-box-shadow:0 0 1px rgba(63,81,181,.9);box-shadow:0 0 1px rgba(63,81,181,.9)}50%{-webkit-transform:rotate(145deg);transform:rotate(145deg);opacity:1}to{-webkit-transform:rotate(-320deg);transform:rotate(-320deg);opacity:0}}\@-webkit-keyframes spinoffPulse{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}\@keyframes spinoffPulse{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.pie-api-player img{max-width:inherit;max-height:inherit}.book-title-k5{text-decoration:underline}.book-title{font-style:italic}.block-quote,.text-block{font-family:serif;margin-left:20%;margin-right:20%;margin-top:5px;margin-bottom:5px;width:60%;border:1px solid #000;padding:2px;display:block}.short-quote{font-weight:700}span.short-quote:before{content:open-quote}span.short-quote:after{content:close-quote}.word-callout{text-decoration:underline}.relative-emphasis{text-transform:uppercase}.content-emphasis{font-weight:700;color:red}span.passage-title:before{content:open-quote}span.passage-title:after{content:close-quote}.proper-name,.variable{font-style:italic}.equation-block{text-align:center;margin-left:20%;margin-right:20%;margin-top:5px;margin-bottom:5px;width:60%;padding:2px;display:block}.embedded-error{font-style:italic}div.passage-subtitle,div.passage-title{font-weight:700;text-align:center}div.passage-author{text-align:center}.p-number{float:left;font-size:.85em}.numbered-paragraph{margin-left:36px}\@media print{.kds-noprint,.noprint{display:none}}.abs,.kds-absolute{border-left:1px solid #000;border-right:1px solid #000;padding:0 .3em 0 .3em}.kds-border-1{border:1px solid #000}.kds-border-2{border:2px solid #000}.center,.kds-center{margin:0;text-align:center}.kds-exponent{font-size:85%}.kds-exponent,sup.frac{margin-left:-.4em;position:relative;top:-1.4em}sup.frac{font-size:70%}.kds-fillin{display:inline-block}.fillin,.kds-fillin{border:1px solid #000;margin:0 .2em;padding-left:1em}.fillin{display:inline-block;*display:inline}.kds-font-larger{font-size:larger}.kds-font-smaller{font-size:smaller}table.kds-fraction{border:0;display:inline-block;font-size:85%;margin:0;padding:0;vertical-align:middle}table.kds-fraction>tbody>tr>td.kds-numerator{border-bottom:1px solid #000;border-left:0;border-right:0;border-top:0;text-align:center}table.kds-fraction>tbody>tr>td.kds-denominator{border:0;text-align:center}table.frac{display:inline-block;*display:inline;vertical-align:middle;font-size:85%;border:0;margin:0;padding:0}.frac .nu{border-left:0;border-top:0;border-right:0;border-bottom:1px solid #000;text-align:center}.frac .de{border:0;text-align:center}.kds-hanging-indent{margin:0;padding-left:3em;text-indent:-3em}.kds-image-caption{font-family:Verdana,Arial,sans-serif;text-align:center}.kds-image-left{float:left;margin-right:5px}.kds-image-right{float:right;margin-left:5px}.indent,.kds-indent{text-indent:3em}.kds-nowrap{display:inline-block;white-space:nowrap}.kds-overline{text-decoration:overline}.kds-parentheses{font-family:Arial Narrow,Arial,sans-serif}.kds-parentheses,b.frac{font-size:300%;font-weight:400;position:relative;top:8px}b.frac{font-family:arial narrow}.kds-pi{font-family:Times New Roman,serif;font-size:1.2em}.newradical{border-collapse:collapse;display:inline-block;*display:inline;vertical-align:middle}.newradical td{border:0;padding:0;vertical-align:top}.newradical td.vinculum{border-top:1px solid #000;padding:0;vertical-align:top}.newradical div.exp{font-size:.7em;position:relative;left:7px;bottom:5px}.kds-underline,.under{text-decoration:underline}.kds-verdana2t,.Verdana2t{border:1px solid #fff;text-align:left;text-decoration:none;vertical-align:top}.kds-whole-number{display:inline-block}.kds-whole-number,.whole{font-size:120%;margin:0 0 0 .2em}.whole{display:inline-block;*display:inline}table.KdsTable01{border:1px solid #000;border-collapse:collapse;border-spacing:0}table.KdsTable01>tbody>tr>th{font-weight:400}table.KdsTable01>tbody>tr>th,table.KdsTable01>tbody>tr>th.bold{background-color:#d3d3d3;border:1px solid #000;padding:2px;text-align:center}table.KdsTable01>tbody>tr>th.bold{font-weight:700}table.KdsTable01>tbody>tr>td,table.KdsTable01>tbody>tr>td.bold{border:1px solid #000;padding:2px;text-align:center}table.KdsTable01>tbody>tr>td.bold{font-weight:700}table.KdsTable02{border:1px solid #000;border-collapse:collapse;border-spacing:0}table.KdsTable02>tbody>tr>th{background-color:#d3d3d3;font-weight:400}table.KdsTable02>tbody>tr>td,table.KdsTable02>tbody>tr>th{border:1px solid #000;padding:2px}.table{width:100%;margin-bottom:1em;background-color:transparent;border-collapse:collapse}.table td,.table th{padding:.75em;vertical-align:top;border-top:1px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}th{text-align:inherit}.table-bordered,.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.text-center{text-align:center!important}.h5,h5{font-size:1.25em}h1,h2,h3,h4,h5,h6{margin-top:0}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5em;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}.lrn_feature h3{margin-top:0!important}#item,#stimulus{width:50%;float:left}.lrn_width_auto.table{width:auto}.TEX-S3{font-family:MJXZERO,MJXTEX-S3!important}.TEX-S2{font-family:MJXZERO,MJXTEX-S2!important}.TEX-S1{font-family:MJXZERO,MJXTEX-S1!important}.TEX-I{font-family:MJXZERO,MJXTEX-I!important}mjx-c.mjx-c2032{font-family:CerebriSans,serif!important}mjx-c.mjx-c22,mjx-c.mjx-c27{font-family:MJXZERO,serif!important}table{border-collapse:collapse}.evaluate-bottom-border>:first-child:after{content:\"\";display:block;border-bottom:1px solid #d3d3d3}"; }
};

exports.pie_author = Author;
