Skip to content

Instantly share code, notes, and snippets.

@lmccart
Created April 25, 2013 18:28
Show Gist options
  • Save lmccart/5461962 to your computer and use it in GitHub Desktop.
Save lmccart/5461962 to your computer and use it in GitHub Desktop.
// Defines common functionality for toggleable components and components that
// may require the selection of files and folders.
//
// This view is intended to be extended (`ComponentBaseView.extend({...})`)
// rather than used directly.
define(['underscore', 'jquery', 'backbone', 'views/modal',
'collections/folders', 'collections/files', 'models/file',
'text!templates/component-toggle.html',
'text!templates/component-manage-files.html',
'text!templates/component-folder-modal.html',
'text!templates/component-file-modal.html'],
function (_, $, Backbone, ModalView,
Folders, Files, File,
componentToggleTmpl,
componentManageFilesTmpl,
componentFolderModalTmpl,
componentFileModalTmpl) {
return Backbone.View.extend({
initialize: function () {
// Add a default set of templates to the view.
this.templates = _.extend({}, this.templates, {
// Renders a toggle button for enabling or disabling the component.
toggle: _.bind(function () {
var templateVars = _.extend({
component: this.model.get(this.component.field)
}, this.component);
return _.template(componentToggleTmpl, templateVars);
}, this),
// Renders buttons to select folders/files for the component, and the
// current selected folders/files.
manageFiles: _.bind(function () {
var templateVars = _.extend({
component: this.model.get(this.component.field),
files: this.model.get(this.component.field).files
}, this.component);
return _.template(componentManageFilesTmpl, templateVars);
}, this),
// Renders a modal dialog for selecting a folder for the component.
folderModal: _.template(componentFolderModalTmpl),
// Renders a modal dialog for selecting files for the component from
// the current active folder.
selectFileModal: _.template(componentFileModalTmpl)
});
// Add a default set of events corresponding to the above templates.
this.events = _.extend({}, this.events, {
'click .btn.disable': 'disable',
'click .btn.enable': 'enable',
'click .btn.choose-folder': 'chooseFolder',
'click .btn.choose-files': 'chooseFiles',
// Make buttons disable & show "Saving..." when clicked.
'click .btn.saves': function (e) {
var button = $(e.currentTarget);
button.data('loading-text', 'Saving...').button('loading');
},
// Make buttons disable & show "Saving..." when clicked.
'click .btn.loads': function (e) {
var button = $(e.currentTarget);
button.data('loading-text', 'Loading...').button('loading');
}
});
},
// Returns true if this view's component is currently enabled for this
// view's model.
isEnabled: function () {
return this.model.get(this.component.field).enabled;
},
// Enables this view's component of this view's model.
enable: function () {
this.model.setEnabled(this.component.field, true);
},
// Disables this view's component of this view's model.
disable: function () {
this.model.setEnabled(this.component.field, false);
},
// Displays the "Select a Folder" modal.
//
// - `trigger` is the event that triggered the modal
// - `folders` is the folders collection to use for listing folders
showFolderModal: function (trigger, folders) {
// Create the modal.
var modal = new ModalView({
title: 'Choose a Folder',
content: this.templates.folderModal({folders: folders})
});
// Persist the checked folder item to the preset model on save.
modal.on('save', _.bind(function (el) {
var selected = el.find('input[name="folder"]:checked').val();
this.model.transform(this.component.field, function (component) {
return _.extend({}, component, {
folder: selected
});
});
this.model.setEnabled(this.component.field, selected);
this.model.save();
this.syncFiles();
}, this));
// Reset the text of the button that triggered the modal, when the modal
// is closed.
modal.on('close', function () {
$(trigger.currentTarget).button('reset');
});
modal.show();
},
// Triggers the "Select a Folder" modal.
chooseFolder: function (e) {
// Fetch folders, and show the modal when they're synced.
var folders = new Folders();
folders.once('sync', function () {
this.showFolderModal(e, folders);
}, this);
folders.fetch();
},
syncFiles: function() {
var files = new Files(this.model, this.component.field);
files.once('sync', function () {
// Get the current set of active files for this preset/component.
var activeFiles = this.model.getActiveFiles(this.component.field);
activeFiles.reset();
console.log(files);
// For each file in selected folder, add it to the collection of active (selected) files.
files.each(function (item) {
if (activeFiles.get(item) === undefined) {
console.log(item);
activeFiles.add(item);
}
});
// Overwrite the "files" property for the preset's component with
// the files from the active collection we just built.
this.model.transform(this.component.field, function (component) {
return _.extend({}, component, {
files: activeFiles.map(function (item) {
return item.attributes;
})
});
});
this.model.save();
}, this);
files.fetch();
},
// Displays the "Select Files" modal.
//
// - `trigger` is the event that triggered the modal
// - `files` is the files collection to use for listing files
showFilesModal: function (trigger, files) {
// Get the current set of active files for this preset/component.
var activeFiles = this.model.getActiveFiles(this.component.field);
// Create the modal.
var modal = new ModalView({
title: 'Select Files',
content: this.templates.selectFileModal({
activeFiles: activeFiles,
files: files
})
});
modal.on('save', _.bind(function (el) {
// For each file in the list of available files, if the file is
// checked, add it to the collection of active (selected) files if
// necessary, otherwise add it if necessary.
files.each(function (item) {
console.log(item);
// Determine whether the corresponding checkbox was checked.
var fileCheck = el.find('input[value="' + item.get('name') + '"]');
var checked = fileCheck.is(':checked');
if (checked && activeFiles.get(item) === undefined) {
activeFiles.add(item);
} else if (!checked && activeFiles.get(item) !== undefined) {
activeFiles.remove(item);
}
});
// Overwrite the "files" property for the preset's component with
// the files from the active collection we just built.
this.model.transform(this.component.field, function (component) {
return _.extend({}, component, {
files: activeFiles.map(function (item) {
return item.attributes;
})
});
});
this.model.save();
}, this));
// Reset the text of the button that triggered the modal, when the modal
// is closed.
modal.on('close', function () {
$(trigger.currentTarget).button('reset');
});
modal.show();
},
// Triggers the "Select Files" modal.
chooseFiles: function (e) {
// Fetch files for the current preset and component, and show the modal
// when they're synced.
var files = new Files(this.model, this.component.field);
files.once('sync', function () {
this.showFilesModal(e, files);
}, this);
files.fetch();
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment