import RestModel from "discourse/models/rest"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; const THEME_UPLOAD_VAR = 2; export const THEMES = "themes"; export const COMPONENTS = "components"; const SETTINGS_TYPE_ID = 5; const Theme = RestModel.extend({ FIELDS_IDS: [0, 1], isActive: Em.computed.or("default", "user_selectable"), isPendingUpdates: Em.computed.gt("remote_theme.commits_behind", 0), hasEditedFields: Em.computed.gt("editedFields.length", 0), @computed("theme_fields") themeFields(fields) { if (!fields) { this.set("theme_fields", []); return {}; } let hash = {}; fields.forEach(field => { if (!field.type_id || this.get("FIELDS_IDS").includes(field.type_id)) { hash[this.getKey(field)] = field; } }); return hash; }, @computed("theme_fields", "theme_fields.@each") uploads(fields) { if (!fields) { return []; } return fields.filter( f => f.target === "common" && f.type_id === THEME_UPLOAD_VAR ); }, @computed("theme_fields", "theme_fields.@each.error") isBroken(fields) { return ( fields && fields.some(field => field.error && field.error.length > 0) ); }, @computed("theme_fields.@each") editedFields(fields) { return fields.filter( field => !Em.isBlank(field.value) && field.type_id !== SETTINGS_TYPE_ID ); }, getKey(field) { return `${field.target} ${field.name}`; }, hasEdited(target, name) { if (name) { return !Em.isEmpty(this.getField(target, name)); } else { let fields = this.get("theme_fields") || []; return fields.any( field => field.target === target && !Em.isEmpty(field.value) ); } }, getError(target, name) { let themeFields = this.get("themeFields"); let key = this.getKey({ target, name }); let field = themeFields[key]; return field ? field.error : ""; }, getField(target, name) { let themeFields = this.get("themeFields"); let key = this.getKey({ target, name }); let field = themeFields[key]; return field ? field.value : ""; }, removeField(field) { this.set("changed", true); field.upload_id = null; field.value = null; return this.saveChanges("theme_fields"); }, setField(target, name, value, upload_id, type_id) { this.set("changed", true); let themeFields = this.get("themeFields"); let field = { name, target, value, upload_id, type_id }; // slow path for uploads and so on if (type_id && type_id > 1) { let fields = this.get("theme_fields"); let existing = fields.find( f => f.target === target && f.name === name && f.type_id === type_id ); if (existing) { existing.value = value; existing.upload_id = upload_id; } else { fields.push(field); } return; } // fast path let key = this.getKey({ target, name }); let existingField = themeFields[key]; if (!existingField) { this.theme_fields.push(field); themeFields[key] = field; } else { existingField.value = value; } }, @computed("childThemes.@each") child_theme_ids(childThemes) { if (childThemes) { return childThemes.map(theme => Ember.get(theme, "id")); } }, removeChildTheme(theme) { const childThemes = this.get("childThemes"); childThemes.removeObject(theme); return this.saveChanges("child_theme_ids"); }, addChildTheme(theme) { let childThemes = this.get("childThemes"); if (!childThemes) { childThemes = []; this.set("childThemes", childThemes); } childThemes.removeObject(theme); childThemes.pushObject(theme); return this.saveChanges("child_theme_ids"); }, @computed("name", "default") description: function(name, isDefault) { if (isDefault) { return I18n.t("admin.customize.theme.default_name", { name: name }); } else { return name; } }, checkForUpdates() { return this.save({ remote_check: true }).then(() => this.set("changed", false) ); }, updateToLatest() { return this.save({ remote_update: true }).then(() => this.set("changed", false) ); }, changed: false, saveChanges() { const hash = this.getProperties.apply(this, arguments); return this.save(hash) .finally(() => this.set("changed", false)) .catch(popupAjaxError); }, saveSettings(name, value) { const settings = {}; settings[name] = value; return this.save({ settings }); } }); export default Theme;