'use strict'; oml.UI = (function() { var previousUI = {}, that = {}; that.encode = function(value) { return value.replace(/\./g, '\\.'); }; that.getPrevious = function(key) { return !key ? previousUI : previousUI[key]; }; that.reset = function() { var ui = oml.user.ui; function reload() { Ox.Request.clearCache() oml.user.ui = ui = oml.config.user.ui; ui._list = oml.getListState(ui.find); ui._filterState = oml.getFilterState(ui.find); ui._findState = oml.getFindState(ui.find); Ox.Theme(ui.theme); oml.$ui.appPanel.reload(); } if (oml.readOnly) { oml.localStorage('ui', oml.config.user.ui); reload(); } else { oml.api.resetUI({}, reload); } }; // sets oml.user.ui.key to value // key foo.bar.baz sets oml.user.ui.foo.bar.baz // value null removes a key that.set = function(/* {key: value}[, flag] or key, value[, flag] */) { var add = {}, args, item, list, listSettings = oml.config.listSettings, listView, set = {}, trigger = {}, triggerEvents, ui = oml.user.ui; if (Ox.isObject(arguments[0])) { args = arguments[0]; triggerEvents = Ox.isUndefined(arguments[1]) ? true : arguments[1]; } else { args = Ox.makeObject([arguments[0], arguments[1]]); triggerEvents = Ox.isUndefined(arguments[2]) ? true : arguments[1]; } Ox.print('UI SET', JSON.stringify(args)); previousUI = Ox.clone(ui, true); previousUI._list = oml.getListState(previousUI.find); if ('find' in args) { // the challenge here is that find may change list, // and list may then change listSort and listView, // which we don't want to trigger, since find triggers // (values we put in add will be changed, but won't trigger) // FIXME: ABOVE COMMENT DOES NOT APPLY list = oml.getListState(args.find); ui._list = list; ui._filterState = oml.getFilterState(args.find); ui._findState = oml.getFindState(args.find); if (oml.$ui.appPanel && !oml.stayInItemView) { // if we're not on page load, and if find isn't a context change // caused by an edit, then switch from item view to list view args.item = ''; } if (list != previousUI._list) { // if find has changed list Ox.forEach(listSettings, function(listSetting, setting) { // then for each setting that corresponds to a list setting if (!ui.lists[list]) { // either add the default setting args[setting] = oml.config.user.ui[setting]; } else { // or the existing list setting args[setting] = ui.lists[list][listSetting]; } }); } } else { list = previousUI._list; } // it is important to check for find first, so that // if find changes list, list is correct here item = args.item || ui.item; listView = add.listView || args.listView; if (!ui.lists[list]) { add['lists.' + that.encode(list)] = {}; } Ox.forEach(listSettings, function(listSetting, setting) { // for each setting that corresponds to a list setting // set that list setting to var key = 'lists.' + that.encode(list) + '.' + listSetting; if (setting in args) { // the setting passed to UI.set or changed via find add[key] = args[setting]; } else if (!ui.lists[list]) { // or the default setting add[key] = oml.config.user.ui[setting]; } }); if (args.item) { // when switching to an item, update list selection add['listSelection'] = [args.item]; add['lists.' + that.encode(list) + '.selection'] = [args.item]; if ( !args.itemView && ui.itemView == 'book' && !ui.mediaState[item] && !args['mediaState.' + item] ) { // if the item view doesn't change, remains a media view, // media state doesn't exist yet, and won't be set, add // default media state add['mediaState.' + item] = {position: 0, zoom: 1}; } } if ( args.itemView == 'book' && !ui.mediaState[item] && !args['mediaState.' + item] ) { // when switching to a media view, media state doesn't exist // yet, and won't be set, add default media state add['mediaState.' + item] = {position: 0, zoom: 1}; } // items in args trigger events, items in add do not [args, add].forEach(function(object, isAdd) { Ox.forEach(object, function(value, key) { // make sure to not split at escaped dots ('\.') var keys = key.replace(/\\\./g, '\n').split('.').map(function(key) { return key.replace(/\n/g, '.'); }), ui_ = ui; while (keys.length > 1) { if (!(keys[0] in ui_)) { ui_[keys[0]] = {}; } ui_ = ui_[keys.shift()]; } if (!Ox.isEqual(ui_[keys[0]], value)) { if (value === null) { delete ui_[keys[0]]; } else { ui_[keys[0]] = value; } set[key] = value; if (!isAdd) { trigger[key] = value; } } }); }); if (Ox.len(set)) { if (oml.readOnly) { oml.localStorage('ui', oml.user.ui); } else { oml.api.setUI(set); } } if (triggerEvents) { Ox.forEach(trigger, function(value, key) { Ox.print('UI TRIGGER', 'oml_' + key.toLowerCase(), value); Ox.forEach(oml.$ui, function($elements) { Ox.makeArray($elements).forEach(function($element) { $element.triggerEvent('oml_' + key.toLowerCase(), { value: value, previousValue: previousUI[key] }); }); }); }); } oml.URL.update(Object.keys(!oml.$ui.appPanel ? args : trigger)); }; return that; }());