define(function(require){ var Origin = require('core/origin'); var OriginView = require('core/views/originView'); var AssetManagementCollectionView = require('./assetManagementCollectionView'); var AssetManagementPreviewView = require('./assetManagementPreviewView'); var AssetManagementView = OriginView.extend({ tagName: 'div', className: 'asset-management', preRender: function() { this.listenTo(Origin, { 'window:resize': this.resizePanels, 'assetManagement:assetItemView:preview': this.onAssetClicked, 'assetManagement:assetPreviewView:delete': this.onAssetDeleted }); }, postRender: function() { var view = new AssetManagementCollectionView({ collection: this.collection }); this.$('.asset-management-assets-container-inner').append(view.$el); this.resizePanels(); // defer setting ready status until images are ready _.defer(function() { view.$el.imageready(this.setViewToReady); }); }, resizePanels: function() { var navigationHeight = $('.navigation').outerHeight(); var locationTitleHeight = $('.location-title').outerHeight(); var windowHeight = $(window).height(); var actualHeight = windowHeight - (navigationHeight + locationTitleHeight); var paneWidth = $('.asset-management').outerWidth(); this.$('.asset-management-assets-container') .height(actualHeight) .width(paneWidth*0.75); this.$('.asset-management-preview-container') .height(actualHeight) .width(paneWidth*0.25); }, onAssetClicked: function(model) { this.$('.asset-management-no-preview').hide(); var view = new AssetManagementPreviewView({ model: model }); this.$('.asset-management-preview-container-inner').html(view.$el); }, onAssetDeleted: function() { this.$('.asset-management-no-preview').show(); } }, { template: 'assetManagement' }); return AssetManagementView; });
define(function(require){ var Handlebars = require('handlebars'); var Backbone = require('backbone'); var Origin = require('core/origin'); var OriginView = require('core/views/originView'); var MenuSettingsView = OriginView.extend({ tagName: 'li', className: function() { var isSelectedClass = (this.model.get('_isSelected')) ? ' selected' : ''; return 'menu-settings-list-item' + isSelectedClass; }, events: { 'click': 'toggleSelect' }, preRender: function() { this.listenTo(Origin, 'editor:menuSettings:selected', this.deselectMenu); }, toggleSelect: function(e) { e && e.stopPropagation(); if (!this.model.get('_isSelected')) { this.selectMenu(); } }, selectMenu: function() { Origin.trigger('editor:menuSettings:selected'); this.$el.addClass('selected'); this.model.set({_isSelected: true}); }, deselectMenu: function() { this.$el.removeClass('selected'); this.model.set({_isSelected: false}); } }, { template: 'editorMenuSettingsItem' }); return MenuSettingsView; });
define(function(require){ var OriginView = require('core/views/originView'); var Origin = require('core/origin'); var NavigationView = OriginView.extend({ tagName: 'nav', className: 'navigation', initialize: function() { this.listenTo(Origin, 'login:changed', this.loginChanged); this.render(); }, events: { 'click a.navigation-item':'onNavigationItemClicked' }, render: function() { var data = this.model ? this.model.toJSON() : null; var template = Handlebars.templates[this.constructor.template]; this.$el.html(template(data)); return this; }, loginChanged: function() { this.render(); }, onNavigationItemClicked: function(event) { event.preventDefault(); event.stopPropagation(); Origin.trigger('navigation:' + $(event.currentTarget).attr('data-event')); } }, { template: 'navigation' }); return NavigationView; });
define(function(require){ var OriginView = require('core/views/originView'); var Origin = require('core/origin'); var Helpers = require('../helpers'); var UserView = OriginView.extend({ tagName: 'div', className: function() { var className = 'user-item tb-row' + ' ' + this.model.get('_id'); // 'current user styling if (this.model.get('_id') === Origin.sessionModel.get('id')) className += ' me'; return className; }, isSelected: false, events: { 'click': 'onClicked', 'click a.edit': 'onEditClicked', 'click a.save': 'onSaveClicked', 'click a.cancel': 'onCancelClicked', 'click a.saveRoles': 'onSaveRoleClicked', 'click button.resetPassword': '******', 'click button.changePassword': '******', 'click button.unlock': 'onResetLoginsClicked', 'click button.disable': 'onDisableClicked', 'click button.delete': 'onDeleteClicked', 'click button.restore': 'onRestoreClicked' }, preRender: function() { this.listenTo(Origin, 'userManagement:user:reset', this.resetView); this.listenTo(this.model, 'destroy', this.remove); this.listenTo(this, 'remove', this.remove); }, render: function() { OriginView.prototype.render.apply(this, arguments); this.applyStyles(); }, applyStyles: function() { // disabled user styling if(this.model.get('_isDeleted') === true) { this.$el.addClass('inactive'); } else { this.$el.removeClass('inactive'); } // locked user styling if(this.model.get('_isLocked') === true) { this.$el.addClass('locked'); } else { this.$el.removeClass('locked'); } // selected user styling if(this.isSelected) { this.$el.addClass('selected'); this.$('.edit-mode').removeClass('display-none'); this.$('.write').addClass('display-none'); } else { this.$el.removeClass('selected'); this.$('.edit-mode').addClass('display-none'); this.$('.write').addClass('display-none'); } }, resetView: function() { if(this.isSelected) { this.isSelected = false; this.applyStyles(); } }, setEditMode: function() { this.editMode = true; this.applyStyles(); }, setViewMode: function() { this.editMode = false; this.applyStyles(); }, // utilities in case the classes change getColumnFromDiv: function(div) { return $(div).closest('.tb-col-inner'); }, getInputFromDiv: function(div) { return $('.input', this.getColumnFromDiv(div)); }, disableFieldEdit: function(div) { $('.read', div).removeClass('display-none'); $('.write', div).addClass('display-none'); }, enableFieldEdit: function(div) { $('.read', div).addClass('display-none'); $('.write', div).removeClass('display-none').children('input').focus(); }, onEditClicked: function(event) { event && event.preventDefault(); var $column = this.getColumnFromDiv(event.currentTarget); // disable any existing inputs first this.disableFieldEdit(this.$el); this.enableFieldEdit($column); var $input = this.getInputFromDiv($column); var inputType = $input.attr('type'); if(inputType === "text" || inputType === "email") { $input.val(this.model.get($input.attr('data-modelKey'))); } }, onClicked: function(event) { if(!this.isSelected) { Origin.trigger('userManagement:user:reset'); this.isSelected = true; this.applyStyles(); } }, onSaveClicked: function(event) { event && event.preventDefault(); var $column = this.getColumnFromDiv(event.currentTarget); this.disableFieldEdit($column); // save if not the same as old value var $input = this.getInputFromDiv($column); if($input.val() && this.model.get($input.attr('data-modelKey')) !== $input.val()) { this.updateModel($input.attr('data-modelKey'), $input.val()); } }, onCancelClicked: function(event) { event && event.preventDefault(); this.disableFieldEdit(this.getColumnFromDiv(event.currentTarget)); }, onSaveRoleClicked: function(event) { event && event.preventDefault(); var $column = this.getColumnFromDiv(event.currentTarget); var $input = this.getInputFromDiv($column); var oldRole = this.model.get('roles')[0]; var newRole = $input.val(); this.disableFieldEdit($column); var self = this; if(newRole && this.model.get($input.attr('data-modelKey')) !== newRole) { Helpers.ajax('api/role/' + oldRole + '/unassign/' + this.model.get('_id'), null, 'POST', function() { Helpers.ajax('api/role/' + newRole + '/assign/' + self.model.get('_id'), null, 'POST', function() { self.model.fetch(); }); }); } }, onResetLoginsClicked: function() { var self = this; Origin.Notify.confirm({ text: Origin.l10n.t('app.confirmresetlogins', { email: this.model.get('email') }), callback: function(confirmed) { if(confirmed) self.updateModel('failedLoginCount', 0); } }); }, onResetPasswordClicked: function(e) { var $btn = $(e.currentTarget); $btn.addClass('submitted'); Helpers.ajax('/api/createtoken', { email: this.model.get('email') }, 'POST', function() { $btn.removeClass('submitted'); }); }, onChangePasswordClicked: function() { var self = this; Origin.Notify.confirm({ type: 'input', title: Origin.l10n.t('app.resetpasswordtitle'), text: Origin.l10n.t('app.resetpasswordinstruction', { email: this.model.get('email') }), inputType: 'password', confirmButtonText: 'Save', closeOnConfirm: false, callback: function(newPassword) { if(newPassword === false) return; else if(newPassword === "") return swal.showInputError(Origin.l10n.t('app.passwordempty')); var postData = { "email": self.model.get('email'), "password": newPassword }; Helpers.ajax('/api/user/resetpassword', postData, 'POST', function() { self.model.fetch(); Origin.Notify.alert({ type: 'success', text: Origin.l10n.t('app.changepasswordtext', { email: self.model.get('email') }) }); }); } }); }, onDisableClicked: function() { this.updateModel('_isDeleted', true); }, onRestoreClicked: function() { this.updateModel('_isDeleted', false); }, onDeleteClicked: function() { var self = this; Origin.Notify.confirm({ type: 'confirm', text: Origin.l10n.t('app.confirmdeleteuser', { email: this.model.get('email') }), callback: function(confirmed) { if(confirmed) { self.model.destroy({ error: self.onError }); } } }); }, updateModel: function(key, value) { var self = this; var toSave = {}; toSave[key] = value; this.model.save(toSave, { patch: true, wait: true, error: function(model, response, options) { var data = { key: key, value: value }; var errorCode = response.responseJSON && response.responseJSON.code; var errorMessage = response.responseText; switch(errorCode) { // duplicate key case 11000: return self.onError(Origin.l10n.t('app.duplicateuservalueerror', data)); default: return self.onError(Origin.l10n.t('app.uservalueerror') + ' (' + errorMessage + ')'); } } }); }, onError: function(error) { /** * HACK setTimeout to make sure the alert opens. * If we've come straight from a confirm, sweetalert will still be cleaning * up, and won't show. */ setTimeout(function() { Origin.Notify.alert({ type: 'error', text: error.message || error }); }, 100); } }, { template: 'user' }); return UserView; });
define(function(require){ var Origin = require('core/origin'); var OriginView = require('core/views/originView'); var ProjectView = require('./projectView'); var ProjectsView = OriginView.extend({ className: 'projects', supportedLayouts: [ "grid", "list" ], preRender: function(options) { OriginView.prototype.preRender.apply(this, arguments); this._isShared = options._isShared; }, postRender: function() { this.settings.preferencesKey = 'dashboard'; this.initUserPreferences(); this.initEventListeners(); this.initPaging(); }, initEventListeners: function() { this._doLazyScroll = _.throttle(this.doLazyScroll, 250).bind(this); this._onResize = _.debounce(this.onResize, 250).bind(this); this.listenTo(Origin, { 'window:resize dashboard:refresh': this._onResize, 'dashboard:dashboardSidebarView:filterBySearch': function(text) { this.doFilter(text) }, 'dashboard:dashboardSidebarView:filterByTags': function(tags) { this.doFilter(null, tags) }, 'dashboard:sort:asc': function() { this.doSort('asc'); }, 'dashboard:sort:desc': function() { this.doSort('desc'); }, 'dashboard:sort:updated': function() { this.doSort('updated'); } }); this.supportedLayouts.forEach(function(layout) { this.listenTo(Origin, 'dashboard:layout:' + layout, function() { this.doLayout(layout); }); }, this); this.listenTo(this.collection, 'add', this.appendProjectItem); $('.contentPane').on('scroll', this._doLazyScroll); }, initUserPreferences: function() { var prefs = this.getUserPreferences(); this.doLayout(prefs.layout); this.doSort(prefs.sort, false); this.doFilter(prefs.search, prefs.tags, false); // set relevant filters as selected $("a[data-callback='dashboard:layout:" + prefs.layout + "']").addClass('selected'); $("a[data-callback='dashboard:sort:" + prefs.sort + "']").addClass('selected'); // need to refresh this to get latest filters prefs = this.getUserPreferences(); Origin.trigger('options:update:ui', prefs); Origin.trigger('sidebar:update:ui', prefs); }, // Set some default preferences getUserPreferences: function() { var prefs = OriginView.prototype.getUserPreferences.apply(this, arguments); if(!prefs.layout) prefs.layout = 'grid'; if(!prefs.sort) prefs.sort = 'asc'; return prefs; }, initPaging: function() { if(this.resizeTimer) { clearTimeout(this.resizeTimer); this.resizeTimer = -1; } // we need to load one course first to check page size this.pageSize = 1; this.resetCollection(function(collection) { var containerHeight = $(window).height()-this.$el.offset().top; var containerWidth = this.$('.projects-inner').width(); var itemHeight = $('.project-list-item').outerHeight(true); var itemWidth = $('.project-list-item').outerWidth(true); var columns = Math.floor(containerWidth/itemWidth); var rows = Math.floor(containerHeight/itemHeight); // columns stack nicely, but need to add extra row if it's not a clean split if((containerHeight % itemHeight) > 0) rows++; this.pageSize = columns*rows; // need another reset to get the actual pageSize number of items this.resetCollection(this.setViewToReady); }.bind(this)); }, getProjectsContainer: function() { return this.$('.projects-list'); }, emptyProjectsContainer: function() { Origin.trigger('dashboard:dashboardView:removeSubViews'); this.getProjectsContainer().empty(); }, appendProjectItem: function(model) { var creator = model.get('createdBy') || { email: Origin.l10n.t('app.unknownuser') }; var name = creator.firstName ? creator.firstName + ' ' + creator.lastName : creator.email; if(this._isShared && name) model.set('creatorName', name); this.getProjectsContainer().append(new ProjectView({ model: model }).$el); }, convertFilterTextToPattern: function(filterText) { var pattern = '.*' + filterText.toLowerCase() + '.*'; return { title: pattern }; }, resetCollection: function(cb) { this.emptyProjectsContainer(); this.fetchCount = 0; this.shouldStopFetches = false; this.collection.reset(); this.fetchCollection(cb); }, fetchCollection: function(cb) { if(this.shouldStopFetches) { return; } this.isCollectionFetching = true; this.collection.fetch({ data: { search: _.extend(this.search, { tags: { $all: this.tags } }), operators : { skip: this.fetchCount, limit: this.pageSize, sort: this.sort } }, success: function(collection, response) { this.isCollectionFetching = false; this.fetchCount += response.length; // stop further fetching if this is the last page if(response.length < this.pageSize) this.shouldStopFetches = true; this.$('.no-projects').toggleClass('display-none', this.fetchCount > 0); if(typeof cb === 'function') cb(collection); }.bind(this) }); }, doLazyScroll: function(e) { if(this.isCollectionFetching) { return; } var $el = $(e.currentTarget); var pxRemaining = this.getProjectsContainer().height() - ($el.scrollTop() + $el.height()); // we're at the bottom, fetch more if (pxRemaining <= 0) this.fetchCollection(); }, doLayout: function(layout) { if(this.supportedLayouts.indexOf(layout) === -1) { return; } this.getProjectsContainer().attr('data-layout', layout); this.setUserPreference('layout', layout); }, doSort: function(sort, fetch) { switch(sort) { case "desc": this.sort = { title: -1 }; break; case "updated": this.sort = { updatedAt: -1 }; break; case "asc": default: sort = "asc"; this.sort = { title: 1 }; } this.setUserPreference('sort', sort); if(fetch !== false) this.resetCollection(); }, doFilter: function(text, tags, fetch) { text = text || ''; this.filterText = text; this.search = this.convertFilterTextToPattern(text); this.setUserPreference('search', text, true); tags = tags || []; this.tags = _.pluck(tags, 'id'); this.setUserPreference('tags', tags, true); if(fetch !== false) this.resetCollection(); }, onResize: function() { this.initPaging(); }, remove: function() { $('.contentPane').off('scroll', this._doLazyScroll); OriginView.prototype.remove.apply(this, arguments); } }, { template: 'projects' }); return ProjectsView; });
define(function(require){ var _ = require('underscore'); var Helpers = require('core/helpers'); var Origin = require('core/origin'); var OriginView = require('core/views/originView'); var PluginManagementUploadView = OriginView.extend({ className: 'pluginManagement-upload-plugin', preRender: function() { Origin.trigger('location:title:update', { title: Origin.l10n.t('app.uploadplugin') }); this.listenTo(Origin, 'pluginManagement:uploadPlugin', this.uploadFile); }, postRender: function() { _.defer(this.setViewToReady); }, uploadFile: function() { if(this.validate()) { $('.loading').show(); this.$('.plugin-form').ajaxSubmit({ success: this.onUploadSuccess, error: this.onUploadError }); } // Return false to prevent the page submitting return false; }, validate: function() { if(_.isEmpty(this.$('form input').val())) { this.$('.field-error').removeClass('display-none'); Origin.trigger('sidebar:resetButtons'); return false; } this.$('.field-error').addClass('display-none'); return true; }, onUploadSuccess: function(data) { Origin.trigger('scaffold:updateSchemas', function() { Origin.Notify.alert({ type: 'success', text: Origin.l10n.t('app.uploadpluginsuccess') }); Origin.trigger('sidebar:resetButtons'); $('.loading').hide(); Origin.router.navigateTo('pluginManagement/' + (data.pluginType || '')); }, this); }, onUploadError: function(data) { Origin.trigger('sidebar:resetButtons'); $('.loading').hide(); var resError = data && data.responseJSON && data.responseJSON.message; var resText = data && data.responseText; var message = resError || resText || ''; Origin.Notify.alert({ type: 'error', title: Origin.l10n.t('app.uploadpluginerror'), text: Helpers.decodeHTML(message) }); Origin.router.navigateTo('pluginManagement/upload'); }, }, { template: 'pluginManagementUpload' }); return PluginManagementUploadView; });
define(function(require) { var Origin = require('core/origin'); var OriginView = require('core/views/originView'); var SidebarFieldsetFilterView = require('./sidebarFieldsetFilterView'); var Backbone = require('backbone'); var Helpers = require('core/helpers'); var SidebarItemView = OriginView.extend({ className: 'sidebar-item', events: { 'click button.editor-common-sidebar-project': 'editProject', 'click button.editor-common-sidebar-config': 'editConfiguration', 'click button.editor-common-sidebar-extensions': 'manageExtensions', 'click button.editor-common-sidebar-menusettings': 'editMenu', 'click button.editor-common-sidebar-select-theme': 'selectTheme', 'click button.editor-common-sidebar-download': 'downloadProject', 'click button.editor-common-sidebar-preview': 'previewProject', 'click button.editor-common-sidebar-preview-force': 'forcePreviewProject', 'click button.editor-common-sidebar-export': 'exportProject', 'click button.editor-common-sidebar-close': 'closeProject', 'click .editor-common-sidebar-preview-wrapper .dropdown button': 'toggleDropdown' }, initialize: function(options) { // Set form on view if (options && options.form) { this.form = options.form; } this.render(); this.listenTo(Origin, 'sidebar:resetButtons', this.resetButtons); this.listenTo(Origin, 'sidebar:views:animateIn', this.animateViewIn); _.defer(_.bind(function() { this.setupView(); if (this.form) { this.setupFieldsetFilters(); this.listenTo(Origin, 'editorSidebar:showErrors', this.onShowErrors); } }, this)); }, postRender: function() { this._onWindowClick = this.onWindowClick.bind(this); this.$dropdown = this.$('.dropdown'); $(window).on('click', this._onWindowClick); }, setupView: function() { this.listenTo(Origin, 'sidebar:views:remove', this.remove); }, setupFieldsetFilters: function() { var fieldsets = this.form.options.fieldsets; if (fieldsets.length > 0) { this.$('.sidebar-item-inner').append(Handlebars.templates['sidebarDivide']({title: 'Filters'})); } _.each(fieldsets, function(fieldset) { this.$('.sidebar-item-inner').append(new SidebarFieldsetFilterView({model: new Backbone.Model(fieldset)}).$el); }, this); }, onShowErrors: function(errors) { this.$('.sidebar-fieldset-filter').removeClass('error'); if (errors) { // If there's error we should reset the save button this.resetButtons(); // Go through each error and see where this error fits in the fieldsets // this way we can notify the user something is invalid on the sidebar filters _.each(errors, function(error, attribute) { _.each(this.form.options.fieldsets, function(fieldset, key) { //var fieldKeys = _.keys(fieldset.fields); if (_.contains(fieldset.fields, attribute)) { // Convert fieldsets legend value to class name var className = Helpers.stringToClassName(fieldset.legend); // Set error message this.$('.sidebar-fieldset-filter-' + className).addClass('error'); } }, this); }, this); } }, updateButton: function(buttonClass, updateText) { this.$(buttonClass) .append(Handlebars.templates['sidebarUpdateButton']({updateText: updateText})) .addClass('sidebar-updating') .attr('disabled', true) .find('span').eq(0).addClass('display-none'); }, resetButtons: function() { var $buttonsSpans = this.$('.sidebar-updating').removeClass('sidebar-updating').attr('disabled', false).find('span'); $buttonsSpans.eq(0).removeClass('display-none'); $buttonsSpans.eq(1).remove(); }, animateViewIn: function() { this.$el.velocity({'left': '0%', 'opacity': 1}, "easeOutQuad"); }, navigateToEditorPage: function(page) { Origin.router.navigateTo('editor/' + Origin.editor.data.course.get('_id') + '/' + page); }, editProject: function() { this.navigateToEditorPage('settings'); }, editConfiguration: function() { this.navigateToEditorPage('config'); }, selectTheme: function() { this.navigateToEditorPage('selecttheme'); }, editMenu: function() { this.navigateToEditorPage('menusettings'); }, manageExtensions: function() { this.navigateToEditorPage('extensions'); }, downloadProject: function() { Origin.trigger('editorCommon:download'); }, previewProject: function() { Origin.trigger('editorCommon:preview', false); }, forcePreviewProject: function() { Origin.trigger('editorCommon:preview', true); }, exportProject: function() { Origin.trigger('editorCommon:export'); }, closeProject: function() { Origin.router.navigateTo('dashboard'); }, toggleDropdown: function(event) { event.stopPropagation(); this.$dropdown.toggleClass('active'); }, onWindowClick: function() { this.$dropdown.removeClass('active'); }, remove: function() { $(window).off('click', this._onWindowClick); OriginView.prototype.remove.apply(this, arguments); } }); return SidebarItemView; })
define(function(require){ var Helpers = require('core/helpers'); var Origin = require('core/origin'); var OriginView = require('core/views/originView'); var AddUserView = OriginView.extend({ tagName: 'div', className: 'addUser', createdUserId: false, preRender: function() { Origin.trigger('location:title:update', { title: Origin.l10n.t('app.addusertitle') }); this.listenTo(Origin, 'userManagement:saveUser', this.saveNewUser); }, postRender: function() { this.setViewToReady(); }, isValid: function() { var email = this.$('input[name=email]').val().trim(); var valid = Helpers.isValidEmail(email); if(valid) { this.$('.field-error').addClass('display-none'); } else { this.$('.field-error').removeClass('display-none'); Origin.Notify.alert({ type: 'error', title: Origin.l10n.t('app.validationfailed'), text: Origin.l10n.t('app.invalidusernameoremail') }); } return valid; }, saveNewUser: function() { if(!this.isValid()) { return; } // submit form data this.$('form.addUser').ajaxSubmit({ error: _.bind(this.onAjaxError, this), success: _.bind(this.onFormSubmitSuccess, this) }); return false; }, goBack: function() { Origin.router.navigateTo('userManagement'); }, onFormSubmitSuccess: function(userData, userStatus, userXhr) { this.createdUserId = userData._id; var self = this; var chosenRole = $('form.addUser select[name=role]').val(); var defaultRole = userData.roles[0]; if(chosenRole !== defaultRole) { // unassign the default role $.ajax('/api/role/' + defaultRole + '/unassign/' + userData._id,{ method: 'POST', error: _.bind(self.onAjaxError, self), success: function() { // assign chosen role $.ajax('/api/role/' + chosenRole + '/assign/' + userData._id,{ method: 'POST', error: _.bind(self.onAjaxError, self), success: _.bind(self.onAjaxSuccess, self) }); } }); } else { this.onAjaxSuccess(); } }, onAjaxSuccess: function() { this.goBack(); }, onAjaxError: function(data, status, error) { // We may have a partially created user, make sure it's gone if(this.createdUserId) { $.ajax('/api/user/' + this.createdUserId, { method: 'DELETE', error: _.bind(this.onAjaxError, this) }); } Origin.Notify.alert({ type: 'error', title: "Couldn't add user", text: data.responseText || error }); } }, { template: 'addUser' }); return AddUserView; });
define(function(require){ var Backbone = require('backbone'); var OriginView = require('core/views/originView'); var Origin = require('core/origin'); var AssetManagementPreviewView = OriginView.extend({ tagName: 'div', className: 'asset-management-preview', events: { 'click a.confirm-select-asset' : 'selectAsset', 'click .asset-preview-edit-button': 'onEditButtonClicked', 'click .asset-preview-delete-button': 'onDeleteButtonClicked', 'click .asset-preview-restore-button': 'onRestoreButtonClicked' }, preRender: function() { this.listenTo(this, 'remove', this.remove); }, selectAsset: function (event) { event && event.preventDefault(); var data = {eventToTrigger: 'assetModal:assetSelected', model: this.model}; Origin.trigger('modal:passThrough', data); }, onEditButtonClicked: function(event) { event.preventDefault(); var assetId = this.model.get('_id'); Origin.router.navigateTo('assetManagement/' + assetId + '/edit'); }, onDeleteButtonClicked: function(event) { event.preventDefault(); Origin.Notify.confirm({ type: 'warning', text: Origin.l10n.t('app.assetconfirmdelete'), callback: _.bind(this.onDeleteConfirmed, this) }); }, onDeleteConfirmed: function(confirmed) { var self = this; if (confirmed) { $.ajax({ url: 'api/asset/trash/' + self.model.get('_id'), type: 'PUT', success: function() { if (Origin.permissions.hasPermissions(["*"])) { self.model.set({_isDeleted: true}); } else { self.model.trigger('destroy', self.model, self.model.collection); } Origin.trigger('assetManagement:assetPreviewView:delete'); self.remove(); }, error: function(data) { Origin.Notify.alert({ type: 'error', text: Origin.l10n.t('app.errordeleteasset', { message: data.message }) }); } }); } }, onRestoreButtonClicked: function(event) { event.preventDefault(); event.preventDefault(); Origin.Notify.confirm({ text: Origin.l10n.t('app.assetconfirmrestore'), callback: _.bind(this.onRestoreConfirmed, this) }); }, onRestoreConfirmed: function(confirmed) { var self = this; if (confirmed) { $.ajax({ url: 'api/asset/restore/' + self.model.get('_id'), type: 'PUT', success: function() { self.model.set({_isDeleted: false}); Origin.trigger('assetManagement:assetPreviewView:delete'); self.remove(); }, error: function(data) { Origin.Notify.alert({ type: 'error', text: Origin.l10n.t('app.errorrestoreasset', { message: data.message }) }); } }); } } }, { template: 'assetManagementPreview' }); return AssetManagementPreviewView; });
define(function(require){ var Backbone = require('backbone'); var Handlebars = require('handlebars'); var OriginView = require('core/views/originView'); var Origin = require('core/origin'); var UserProfileView = OriginView.extend({ tagName: 'div', className: 'user-profile', events: { 'click a.change-password' : 'togglePassword', 'keyup #password' : 'onPasswordKeyup', 'keyup #passwordText' : 'onPasswordTextKeyup', 'click .toggle-password' : 'togglePasswordView' }, preRender: function() { this.listenTo(Origin, 'userProfileSidebar:views:save', this.saveUser); this.listenTo(this.model, 'invalid', this.handleValidationError); this.listenTo(this.model, 'change:_isNewPassword', this.togglePasswordUI); this.model.set('_isNewPassword', false); }, postRender: function() { this.setViewToReady(); }, handleValidationError: function(model, error) { Origin.trigger('sidebar:resetButtons'); if (error && _.keys(error).length !== 0) { _.each(error, function(value, key) { this.$('#' + key + 'Error').text(value); }, this); this.$('.error-text').removeClass('display-none'); } }, togglePassword: function(event) { event && event.preventDefault(); // convert to bool and invert this.model.set('_isNewPassword', !!!this.model.get('_isNewPassword')); }, togglePasswordUI: function(model, showPaswordUI) { var formSelector = 'div.change-password-section .form-group .inner'; var buttonSelector = '.change-password'; if (showPaswordUI) { this.$(formSelector).removeClass('display-none'); this.$(buttonSelector).text(Origin.l10n.t('app.cancel')); } else { this.$(buttonSelector).text(Origin.l10n.t('app.changepassword')); this.$(formSelector).addClass('display-none'); this.$('#password').val('').removeClass('display-none'); this.$('#passwordText').val('').addClass('display-none'); this.$('.toggle-password i').addClass('fa-eye').removeClass('fa-eye-slash'); this.$('.toggle-password').addClass('display-none'); this.$('#passwordError').html(''); this.model.set('password', ''); } }, togglePasswordView: function() { event && event.preventDefault(); this.$('#passwordText').toggleClass('display-none'); this.$('#password').toggleClass('display-none'); this.$('.toggle-password i').toggleClass('fa-eye').toggleClass('fa-eye-slash'); }, indicatePasswordStrength: function(event) { var password = $('#password').val(); var $passwordStrength = $('#passwordError'); // Must have capital letter, numbers and lowercase letters var strongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g"); // Must have either capitals and lowercase letters or lowercase and numbers var mediumRegex = new RegExp("^(?=.{7,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$", "g"); // Must be at least 8 characters long var okRegex = new RegExp("(?=.{8,}).*", "g"); if (okRegex.test(password) === false) { var classes = 'alert alert-error'; var htmlText = Origin.l10n.t('app.validationlength', {length: 8}); } else if (strongRegex.test(password)) { var classes = 'alert alert-success'; var htmlText = Origin.l10n.t('app.passwordindicatorstrong'); } else if (mediumRegex.test(password)) { var classes = 'alert alert-info'; var htmlText = Origin.l10n.t('app.passwordindicatormedium'); } else { var classes = 'alert alert-info'; var htmlText = Origin.l10n.t('app.passwordindicatorweak'); } $passwordStrength.removeClass().addClass(classes).html(htmlText); }, saveUser: function() { var self = this; this.$('.error-text').addClass('display-none'); var toChange = { 'firstName': self.$('#firstName').val().trim(), 'lastName': self.$('#lastName').val().trim() }; if (self.model.get('_isNewPassword')) { toChange._isNewPassword = true; toChange.password = self.$('#password').val(); } else { self.model.unset('password'); } _.extend(toChange, { _id: self.model.get('_id'), email: self.model.get('email') }); self.model.save(toChange, { patch: true, error: function(model, response, optinos) { Origin.Notify.alert({ type: 'error', text: Origin.l10n.t('app.errorgeneric') }); }, success: function(model, response, options) { Backbone.history.history.back(); } }); }, onPasswordKeyup: function() { if(this.$('#password').val().length > 0) { this.$('#passwordText').val(this.$('#password').val()); this.indicatePasswordStrength(); this.$('.toggle-password').removeClass('display-none'); } else { this.$('.toggle-password').addClass('display-none'); } }, onPasswordTextKeyup: function() { } }, { template: 'userProfile' }); return UserProfileView; });
define(function(require) { var _ = require('underscore'); var Backbone = require('backbone'); var Handlebars = require('handlebars'); var OriginView = require('core/views/originView'); var Origin = require('core/origin'); var Helpers = require('core/helpers'); var ProjectView = OriginView.extend({ className: 'project-list-item', tagName: 'li', events: { 'dblclick': 'editProject', 'click': 'selectProject', 'click a.open-context-course': 'openContextMenu', 'click a.course-delete': 'deleteProjectPrompt', 'click .projects-details-tags-button-show': 'onProjectShowTagsButtonClicked', 'click .projects-details-tags-button-hide': 'onProjectHideTagsButtonClicked', }, preRender: function() { this.listenTo(this, { 'remove': this.remove, 'contextMenu:course:editSettings': this.editProjectSettings, 'contextMenu:course:edit': this.editProject, 'contextMenu:course:delete': this.deleteProjectPrompt, 'contextMenu:course:copy': this.duplicateProject, 'contextMenu:course:copyID': this.copyIdToClipboard }); this.listenTo(Origin, { 'dashboard:dashboardView:removeSubViews': this.remove, 'dashboard:projectView:itemSelected': this.deselectItem, 'dashboard:dashboardView:deselectItem': this.deselectItem }); this.listenTo(Origin, 'editorView:deleteProject:' + this.model.get('_id'), this.deleteProject); this.model.set('heroImageURI', this.model.getHeroImageURI()); }, openContextMenu: function(event) { if(event) { event.stopPropagation(); event.preventDefault(); } Origin.trigger('contextMenu:open', this, event); }, editProjectSettings: function(event) { event && event.preventDefault(); Origin.router.navigateTo('editor/' + this.model.get('_id') + '/settings'); }, editProject: function(event) { event && event.preventDefault(); Origin.router.navigateTo('editor/' + this.model.get('_id') + '/menu'); }, selectProject: function(event) { event && event.preventDefault(); this.selectItem(); }, selectItem: function() { Origin.trigger('dashboard:projectView:itemSelected'); this.$el.addClass('selected'); this.model.set({ _isSelected: true }); }, deselectItem: function() { this.$el.removeClass('selected'); this.model.set({ _isSelected: false }); }, deleteProjectPrompt: function(event) { event && event.preventDefault(); if(this.model.get('_isShared') === true) { if(this.model.get('createdBy') === Origin.sessionModel.id){ Origin.Notify.confirm({ type: 'warning', title: Origin.l10n.t('app.deletesharedproject'), text: Origin.l10n.t('app.confirmdeleteproject') + '<br/><br/>' + Origin.l10n.t('app.confirmdeletesharedprojectwarning'), destructive: true, callback: _.bind(this.deleteProjectConfirm, this) }); } else { Origin.Notify.alert({ type: 'error', text: Origin.l10n.t('app.errorpermission') }); } return; } Origin.Notify.confirm({ type: 'warning', title: Origin.l10n.t('app.deleteproject'), text: Origin.l10n.t('app.confirmdeleteproject') + '<br/><br/>' + Origin.l10n.t('app.confirmdeleteprojectwarning'), callback: _.bind(this.deleteProjectConfirm, this) }); }, deleteProjectConfirm: function(confirmed) { if (confirmed) { var id = this.model.get('_id'); Origin.trigger('editorView:deleteProject:' + id); } }, deleteProject: function(event) { this.model.destroy({ success: _.bind(this.remove, this), error: function(model, response, options) { _.delay(function() { Origin.Notify.alert({ type: 'error', text: response.responseJSON.message }); }, 1000); } }); }, duplicateProject: function() { $.ajax({ url: this.model.getDuplicateURI(), success: function (data) { Origin.router.navigateTo('editor/' + data.newCourseId + '/settings'); }, error: function() { Origin.Notify.alert({ type: 'error', text: Origin.l10n.t('app.errorduplication') }); } }); }, copyIdToClipboard: function() { var id = this.model.get('_id'); if(Helpers.copyStringToClipboard(id)) { Origin.Notify.alert({ type: 'success', text: Origin.l10n.t('app.copyidtoclipboardsuccess', { id: id }) }); return; } Origin.Notify.alert({ type: 'warning', text: Origin.l10n.t('app.app.copyidtoclipboarderror', { id: id }) }); }, onProjectShowTagsButtonClicked: function(event) { if(event) { event.preventDefault(); event.stopPropagation(); } this.$('.tag-container').show().velocity({ opacity: 1 }); }, onProjectHideTagsButtonClicked: function(event) { if(event) { event.preventDefault(); event.stopPropagation(); } this.$('.tag-container').velocity({ opacity: 0 }).hide(); } }, { template: 'project' }); return ProjectView; });
define(function(require){ var OriginView = require('core/views/originView'); var Origin = require('core/origin'); var AssetManagementNewAssetView = OriginView.extend({ className: 'asset-management-modal-new-asset', events: { 'change .asset-file': 'onChangeFile', 'click .asset-management-modal-new-asset-close': 'onCloseClicked', 'click .asset-management-modal-new-asset-upload': 'onUploadClicked' }, preRender: function() { this.listenTo(Origin, { 'assetManagement:modal:newAssetOpened': this.remove, 'assetManagement:newAsset': this.uploadAsset }); }, onCloseClicked: function(event) { event.preventDefault(); this.remove(); }, onUploadClicked: function(event) { event.preventDefault(); this.uploadAsset(); }, postRender: function() { // tagging this.$('#tags_control').selectize({ create: true, labelField: 'title', load: function(query, callback) { $.ajax({ url: 'api/autocomplete/tag', method: 'GET', error: callback, success: callback }); }, onItemAdd: this.onAddTag.bind(this), onItemRemove: this.onRemoveTag.bind(this), searchField: [ 'title' ] }); // Set view to ready this.setViewToReady(); }, onChangeFile: function(event) { var $title = this.$('.asset-title'); // Default 'title' -- remove C:\fakepath if it is added $title.val(this.$('.asset-file')[0].value.replace("C:\\fakepath\\", "")); }, validateInput: function () { var $uploadFile = this.$('.asset-file'); var validated = true; var $uploadFileErrormsg = $uploadFile.prev('label').find('span.error'); $.each(this.$('.required'), function (index, el) { var $errormsg = $(el).prev('label').find('span.error'); if (!$.trim($(el).val())) { validated = false; $(el).addClass('input-error'); $errormsg.text(Origin.l10n.t('app.pleaseentervalue')); } else { $(el).removeClass('input-error'); $errormsg.text(''); } }); if(!$uploadFile.val()) { validated = false; $uploadFile.addClass('input-error'); $uploadFileErrormsg.text(Origin.l10n.t('app.pleaseaddfile')); } else { $uploadFile.removeClass('input-error'); $uploadFileErrormsg.text(''); } return validated; }, uploadAsset: function() { if (!this.validateInput()) { return false; } var title = this.$('.asset-title').val(); var description = this.$('.asset-description').val(); // If model is new then uploadFile if (this.model.isNew()) { this.uploadFile(); // Return false to prevent the page submitting return false; } else { // Else just update the title, description and tags this.model.set({title: title, description: description}); this.model.save(null, { error: function(model, response, options) { Origin.Notify.alert({ type: 'error', text: Origin.l10n.t('app.errorassetupdate') }); }, success: _.bind(function(model, response, options) { Origin.trigger('assetManagement:collection:refresh', true); this.remove(); }, this) }) } }, uploadFile: function() { // fix tags var tags = []; _.each(this.model.get('tags'), function (item) { item._id && tags.push(item._id); }); this.$('#tags').val(tags); this.$('.asset-form').ajaxSubmit({ uploadProgress: function(event, position, total, percentComplete) { $(".progress-container").css("visibility", "visible"); var percentVal = percentComplete + '%'; $(".progress-bar").css("width", percentVal); $('.progress-percent').html(percentVal); }, error: function(xhr, status, error) { Origin.Notify.alert({ type: 'error', text: xhr.responseJSON.message }); }, success: _.bind(function(data, status, xhr) { Origin.once('assetManagement:assetManagementCollection:fetched', function() { Origin.trigger('assetManagement:modal:selectItem', data._id); }) Origin.trigger('assetManagement:collection:refresh', true); this.remove(); }, this) }); // Return false to prevent the page submitting return false; }, onAddTag: function (tag) { var model = this.model; $.ajax({ url: 'api/content/tag', method: 'POST', data: { title: tag } }).done(function (data) { if (data && data._id) { var tags = model.get('tags') || []; tags.push({ _id: data._id, title: data.title }); model.set({ tags: tags }); } }); }, onRemoveTag: function (tag) { var tags = []; _.each(this.model.get('tags'), function (item) { if (item.title !== tag) { tags.push(item); } }); this.model.set({ tags: tags }); } }, { template: 'assetManagementModalNewAsset' }); return AssetManagementNewAssetView; });
define(function(require) { var Origin = require('core/origin'); var OriginView = require('core/views/originView'); var AssetManagementModalTagsView = OriginView.extend({ className: 'asset-management-modal-tags sidebar-filter', events: { 'click .asset-management-modal-tags-toolbar-close': 'onCloseButtonClicked', 'keydown .asset-management-modal-tags-search-input': 'onSearchKeyDown', 'keyup .asset-management-modal-tags-search-input': 'onSearchKeyUp', 'click .asset-management-modal-tags-item': 'onFilterItemClicked' }, initialize: function(options) { this.data = {}; this.data.title = options.title; this.data.items = options.items; this.listenTo(Origin, 'remove:views', this.remove); this.listenTo(Origin, 'assetManagement:modalTags:remove', this.remove); this.render(); }, render: function() { var template = Handlebars.templates[this.constructor.template]; this.$el.html(template(this.data)); _.defer(_.bind(function() { this.postRender(); }, this)); return this; }, postRender: function() { // Position filter to filter button var offsetLeft = $('.asset-management-modal-add-tag').offset().left; this.$el.css({'left': offsetLeft, 'display': 'block'}); // Bring focus to the filter input field this.$('.asset-management-modal-tags-search-input').focus(); // First item should be selected so the user can press enter this.$('.asset-management-modal-tags-item').first().addClass('selected'); }, onCloseButtonClicked: function() { this.remove(); }, onSearchKeyDown: function(event) { // This is to stop the cursor moving around the input // element when pressing up and down if (event.which === 38) { event.preventDefault(); } if (event.which === 40) { event.preventDefault(); } }, onSearchKeyUp: function(event) { // Check whether the key pressed is up or down if (event.which === 38) { return this.moveUpThroughItems(); } if (event.which === 40) { return this.moveDownThroughItems(); } if (event.which === 13) { return this.addFilter(); } this.searchItems(event); }, moveUpThroughItems: function() { // Check if the element is the first one // as the first item cannot go any further var $selectedItem = this.$('.asset-management-modal-tags-item.selected'); var $prevItem = $selectedItem.prevAll('.asset-management-modal-tags-item:visible:first'); // First check if there's any more visible elements to navigate through if ($prevItem.length === 0) { return; } if (!$selectedItem.is(':first-child')) { this.$('.asset-management-modal-tags-item.selected') .removeClass('selected') .prevAll('.asset-management-modal-tags-item:visible:first') .addClass('selected') .focus(); this.$('.asset-management-modal-tags-search-input').focus(); } }, moveDownThroughItems: function() { // Check if the element is the last visible one // as the last item cannot go any further var $selectedItem = this.$('.asset-management-modal-tags-item.selected'); var $nextItem = $selectedItem.nextAll('.asset-management-modal-tags-item:visible:first'); // First check if there's any more visible elements to navigate through if ($nextItem.length === 0) { return; } if (!$selectedItem.is(':last-child')) { this.$('.asset-management-modal-tags-item.selected') .removeClass('selected') .nextAll('.asset-management-modal-tags-item:visible:first') .addClass('selected') .focus(); this.$('.asset-management-modal-tags-search-input').focus(); } }, searchItems: function(event) { var searchText = $(event.currentTarget).val().toLowerCase(); this.$('.asset-management-modal-tags-item').removeClass('selected'); this.$('.asset-management-modal-tags-item').each(function(event) { var itemText = $('.asset-management-modal-tags-item-inner', $(this)).text().toLowerCase(); if (itemText.indexOf(searchText) > -1) { $(this).removeClass('display-none'); } else { $(this).addClass('display-none'); } }); // Should always select the top one on search this.$('.asset-management-modal-tags-item:visible:first').addClass('selected').focus(); this.$('.asset-management-modal-tags-search-input').focus(); }, addFilter: function() { var selectedTag = { title: this.$('.asset-management-modal-tags-item.selected').attr('data-title'), id: this.$('.asset-management-modal-tags-item.selected').attr('data-id') }; // TODO - fix these events up Origin.trigger('assetManagement:modalTags:filterByTags', selectedTag); this.remove(); }, onFilterItemClicked: function(event) { this.$('.asset-management-modal-tags-item').removeClass('selected'); $(event.currentTarget).addClass('selected'); this.addFilter(); } }, { template: 'assetManagementModalTags' }); return AssetManagementModalTagsView; })