Skip to content

Instantly share code, notes, and snippets.

@wimleers
Created August 27, 2012 15:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wimleers/3489499 to your computer and use it in GitHub Desktop.
Save wimleers/3489499 to your computer and use it in GitHub Desktop.
Edit -> use Create.js
diff --git a/edit.module b/edit.module
index d126f40..bc5de1a 100644
--- a/edit.module
+++ b/edit.module
@@ -112,11 +112,32 @@ function edit_library() {
$wysiwyg_module = variable_get(EDIT_WYSIWYG_VARIABLE, EDIT_WYSIWYG_DEFAULT);
$path = drupal_get_path('module', 'edit');
+
+ $libraries['edit.createjs'] = array(
+ 'title' => 'CreateJS and deps',
+ 'website' => 'http://createjs.org',
+ 'version' => NULL,
+ 'js' => array(
+ libraries_get_path('underscore') . '/underscore-min.js' => array(),
+ libraries_get_path('backbone') . '/backbone-min.js' => array(),
+ drupal_get_path('module', 'edit') . '/js/vie.js' => array(),
+ drupal_get_path('module', 'jquery_update') . '/replace/ui/ui/jquery.ui.widget.js' => array(),
+ drupal_get_path('module', 'edit') . '/js/create.js' => array(),
+ // libraries_get_path('vie') .'/vie-min.js',
+ // libraries_get_path('create') .'/create-min.js',
+ )
+ );
$libraries['edit.frontend'] = array(
'title' => 'Edit: front-end',
'website' => 'http://drupal.org/project/edit',
'version' => NULL, // @TODO Figure out the correct way to do this.
'js' => array(
+ $path . '/js/editable.js' => array(
+ ),
+ $path . '/js/formwidget.js' => array(
+ ),
+ $path . '/js/views.js' => array(
+ ),
$path . '/js/edit.js' => array(
// @TODO Make sure that a subset of the JavaScript is loaded ASAP, so
// that the view/edit mode toggle works immediately.
@@ -154,6 +175,7 @@ function edit_library() {
array('system', 'jquery.form'),
array('system', 'drupal.form'),
array('system', 'drupal.ajax'),
+ array('edit', 'edit.createjs'),
),
);
diff --git a/js/ajax.js b/js/ajax.js
index 840bac7..2e02953 100644
--- a/js/ajax.js
+++ b/js/ajax.js
@@ -110,7 +110,7 @@ $(function() {
}
// Make the freshly rendered field(s) in-place-editable again.
- Drupal.edit.startEditableFields(Drupal.edit.findEditableFields($parent));
+ Drupal.edit.startEditableWidgets(Drupal.edit.util.findEditableFields($parent));
}
};
});
diff --git a/js/edit.js b/js/edit.js
index 213e994..146e54e 100644
--- a/js/edit.js
+++ b/js/edit.js
@@ -11,10 +11,8 @@ Drupal.behaviors.edit = {
$('#edit_view-edit-toggles').once('edit-init', Drupal.edit.init);
$('#edit_view-edit-toggles').once('edit-toggle', Drupal.edit.toggle.render);
- // TODO: remove this; this is to make the current prototype somewhat usable.
- $('a.edit_view-edit-toggle').click(function() {
- $(this).trigger('click.edit');
- });
+ // Remove URLs for the edit toggle links so we don't get redirects
+ $("a.edit_view-edit-toggle").attr('href', '#');
}
};
@@ -24,28 +22,29 @@ Drupal.edit.const.transitionEnd = "transitionEnd.edit webkitTransitionEnd.edit t
Drupal.edit.init = function() {
// VIE instance for Editing
Drupal.edit.vie = new VIE();
- Drupal.edit.vie.use(new Drupal.edit.vie.RdfaService());
- Drupal.edit.state = {};
// We always begin in view mode.
- Drupal.edit.state.isViewing = true;
- Drupal.edit.state.entityBeingHighlighted = [];
- Drupal.edit.state.fieldBeingHighlighted = [];
- Drupal.edit.state.fieldBeingEdited = [];
- Drupal.edit.state.higlightedEditable = null;
- Drupal.edit.state.editedEditable = null;
- Drupal.edit.state.queues = {};
- Drupal.edit.state.wysiwygReady = false;
-
- // Build inventory.
- var IDMapper = function() { return Drupal.edit.getID($(this)); };
- Drupal.edit.state.entities = Drupal.edit.findEditableEntities().map(IDMapper);
- Drupal.edit.state.fields = Drupal.edit.findEditableFields().map(IDMapper);
- console.log('Entities:', Drupal.edit.state.entities.length, ';', Drupal.edit.state.entities);
- console.log('Fields:', Drupal.edit.state.fields.length, ';', Drupal.edit.state.fields);
+ Drupal.edit.state = {
+ isViewing: true,
+ entityBeingHighlighted: [],
+ fieldBeingHighlighted: [],
+ fieldBeingEdited: [],
+ higlightedEditable: null,
+ editedEditable: null,
+ queues: {},
+ wysiwygReady: false
+ };
+
+ // Load the storage widget to get localStorage support
+ $('body').midgardStorage({
+ vie: Drupal.edit.vie,
+ editableNs: 'createeditable'
+ });
// Form preloader.
- Drupal.edit.state.queues.preload = Drupal.edit.findEditableFields().filter('.edit-type-form').map(IDMapper);
+ Drupal.edit.state.queues.preload = Drupal.edit.util.findEditableFields().filter('.edit-type-form').map(function () {
+ return Drupal.edit.util.getID($(this));
+ });
console.log('Fields with (server-generated) forms:', Drupal.edit.state.queues.preload);
// Initialize WYSIWYG, if any.
@@ -69,165 +68,95 @@ Drupal.edit.init = function() {
$('a.edit_view-edit-toggle.edit-' + (isViewing ? 'view' : 'edit')).parent().addClass('active');
if (wasViewing && !isViewing) {
- $(Drupal.theme('editOverlay', {}))
- .appendTo('body')
- .addClass('edit-animate-slow edit-animate-invisible')
- .bind('click.edit', Drupal.edit.clickOverlay);;
-
- var $f = Drupal.edit.findEditableFields();
- Drupal.edit.startEditableFields($f);
- var $e = Drupal.edit.findEditableEntities();
- // Drupal.edit.startEditableEntities($e);
-
- // TODO: preload forms. We could do one request per form, but that's more
- // RTTs than needed. Instead, the server should support batch requests.
- console.log('Preloading forms that we might need!', Drupal.edit.state.queues.preload);
-
- // Animations.
- $('#edit_overlay').css('top', $('#navbar').outerHeight());
- $('#edit_overlay').removeClass('edit-animate-invisible');
-
- // Disable contextual links in edit mode.
- $('.contextual-links-region')
- .addClass('edit-contextual-links-region')
- .removeClass('contextual-links-region');
- }
- else if (!wasViewing && isViewing) {
- // Animations.
- $('#edit_overlay')
- .addClass('edit-animate-invisible')
- .bind(Drupal.edit.const.transitionEnd, function(e) {
- $('#edit_overlay, .edit-form-container, .edit-toolbar-container, #edit_modal, #edit_backstage, .edit-curtain').remove();
- });
-
- var $f = Drupal.edit.findEditableFields();
- Drupal.edit.stopEditableFields($f);
- var $e = Drupal.edit.findEditableEntities();
- Drupal.edit.stopEditableEntities($e);
-
- // Re-enable contextual links in view mode.
- $('.edit-contextual-links-region')
- .addClass('contextual-links-region')
- .removeClass('edit-contextual-links-region');
- }
- else {
- // No state change.
+ Drupal.edit.enterEditState();
+ } else if (!wasViewing && isViewing) {
+ Drupal.edit.enterViewState();
}
return false;
});
};
-Drupal.edit.findEditableEntities = function(context) {
- return Drupal.edit.vie.service('rdfa').readEntities(context || Drupal.settings.edit.context);
-};
-
-Drupal.edit.findEditableFields = function(context) {
- var entities = Drupal.edit.findEditableEntities(context);
- var fields = [];
- _.each(entities, function (entity) {
- fields.push(Drupal.edit.vie.service('rdfa').findPredicateElements(entity.getSubject(), context));
- });
- return fields;
-};
+Drupal.edit.enterEditState = function () {
+ $(Drupal.theme('editOverlay', {}))
+ .appendTo('body')
+ .addClass('edit-animate-slow edit-animate-invisible')
+ .bind('click.edit', Drupal.edit.clickOverlay);
-/*
- * findEditableFields() just looks for fields that are editable, i.e. for the
- * field *wrappers*. Depending on the field, however, either the whole field wrapper
- * will be marked as editable (in this case, an inline form will be used for editing),
- * *or* a specific (field-specific even!) DOM element within that field wrapper will be
- * marked as editable.
- * This function is for finding the *editables* themselves, given the *editable fields*.
- */
-Drupal.edit.findEditablesForFields = function($fields) {
- var $editables = $();
+ var $e = Drupal.edit.util.findEditableFields();
+ Drupal.edit.startEditableWidgets($e);
- // type = form
- $editables = $editables.add($fields.filter('.edit-type-form'));
+ // TODO: preload forms. We could do one request per form, but that's more
+ // RTTs than needed. Instead, the server should support batch requests.
+ console.log('Preloading forms that we might need!', Drupal.edit.state.queues.preload);
- // type = direct
- var $direct = $fields.filter('.edit-type-direct');
- $editables = $editables.add($direct.find('.field-item'));
- // Edge case: "title" pseudofield on pages with lists of nodes.
- $editables = $editables.add($direct.filter('h2').find('a'));
- // Edge case: "title" pseudofield on node pages.
- $editables = $editables.add($direct.find('h1'));
+ // Animations.
+ $('#edit_overlay').css('top', $('#navbar').outerHeight());
+ $('#edit_overlay').removeClass('edit-animate-invisible');
- return $editables;
+ // Disable contextual links in edit mode.
+ $('.contextual-links-region')
+ .addClass('edit-contextual-links-region')
+ .removeClass('contextual-links-region');
};
-Drupal.edit.getID = function($field) {
- return $field.data('edit-id');
-};
+Drupal.edit.enterViewState = function () {
+ // Animations.
+ $('#edit_overlay')
+ .addClass('edit-animate-invisible')
+ .bind(Drupal.edit.const.transitionEnd, function(e) {
+ $('#edit_overlay, .edit-form-container, .edit-toolbar-container, #edit_modal, #edit_backstage, .edit-curtain').remove();
+ });
-Drupal.edit.findFieldForID = function(id, context) {
- return $('[data-edit-id="' + id + '"]', context || $('#content'));
-};
+ var $e = Drupal.edit.util.findEditableFields();
+ Drupal.edit.stopEditableWidgets($e);
-Drupal.edit.findFieldForEditable = function($editable) {
- return $editable.filter('.edit-type-form').length ? $editable : $editable.closest('.edit-type-direct');
+ // Re-enable contextual links in view mode.
+ $('.edit-contextual-links-region')
+ .addClass('contextual-links-region')
+ .removeClass('edit-contextual-links-region');
};
-Drupal.edit.findEntityForField = function($f) {
- var $e = $f.closest('.edit-entity');
- if ($e.length == 0) {
- var entity_edit_id = $f.data('edit-id').split(':').slice(0,2).join(':');
- $e = $('.edit-entity[data-edit-id="' + entity_edit_id + '"]');
- }
- return $e;
-};
+Drupal.edit.startEditableWidgets = function($fields) {
+ var self = this;
-Drupal.edit.findEntityForEditable = function($editable) {
- return Drupal.edit.findEntityForField(Drupal.edit.findFieldForEditable($editable));
-};
+ var enabler = function () {
+ if (Drupal.edit.state.isViewing) {
+ $(this).unbind('click', enabler);
+ return;
+ }
-Drupal.edit.startEditableEntities = function($e) {
- $e
- .once('edit')
- .addClass('edit-animate-fast')
- .addClass('edit-candidate edit-editable')
- .bind('mouseenter.edit', function(e) {
- var $e = $(this);
- Drupal.edit.util.ignoreHoveringVia(e, '.edit-toolbar-container', function() {
- if (Drupal.edit.state.fieldBeingEdited.length > 0) {
- return;
- }
+ // Make the fields editable
+ Drupal.edit.editables.startEdit($(this));
+ return false;
+ };
+
+ $fields
+ .each(function() {
+ var $field = jQuery(this);
- console.log('entity:mouseenter');
- Drupal.edit.entityEditables.startHighlight($e);
+ $field.bind('createeditableenable', function (event, data) {
+ $field.unbind('click.edit', enabler);
+ Drupal.edit.editables._updateDirectEditable($field);
});
- })
- .bind('mouseleave.edit', function(e) {
- var $e = $(this);
- Drupal.edit.util.ignoreHoveringVia(e, '.edit-toolbar-container', function() {
- console.log('entity:mouseleave');
- Drupal.edit.entityEditables.stopHighlight($e);
+
+ $field.bind('createeditabledisable', function (event, data) {
+ $field.bind('click.edit', enabler);
+ $field.removeClass('ui-state-disabled');
+ Drupal.edit.editables._restoreDirectEditable($field);
+ });
+
+ var entity = Drupal.edit.util.getElementEntity(this, Drupal.edit.vie);
+ $field.createEditable({
+ model: entity,
+ vie: Drupal.edit.vie,
+ disabled: true
});
- })
- // Hang a curtain over the comments if they're inside the entity.
- .find('.comment-wrapper').prepend(Drupal.theme('editCurtain', {}))
- .map(function() {
- var height = $(this).height();
- $(this).find('.edit-curtain')
- .css('height', height)
- .data('edit-curtain-height', height);
});
-};
-Drupal.edit.stopEditableEntities = function($e) {
- $e
- .removeClass('edit-processed edit-candidate edit-editable edit-highlighted')
- .unbind('mouseenter.edit mouseleave.edit')
- .find('.comment-wrapper .edit-curtain').remove();
+ Drupal.edit.decorateEditables(Drupal.edit.util.findEditablesForFields($fields));
};
-Drupal.edit.startEditableFields = function($fields) {
- var $fields = $fields.once('edit');
- // Ignore fields that need a WYSIWYG editor if no WYSIWYG editor is present
- if (!Drupal.settings.edit.wysiwyg) {
- $fields = $fields.filter(':not(.edit-type-direct-with-wysiwyg)');
- }
- var $editables = Drupal.edit.findEditablesForFields($fields);
-
+Drupal.edit.decorateEditables = function($editables) {
$editables
.addClass('edit-animate-fast')
.addClass('edit-candidate edit-editable')
@@ -250,15 +179,19 @@ Drupal.edit.startEditableFields = function($fields) {
Drupal.edit.editables.stopHighlight($editable);
// Leaving a field won't trigger the mouse enter event for the entity
// because the entity contains the field. Hence, do it manually.
- var $e = Drupal.edit.findEntityForEditable($editable);
+ var $e = Drupal.edit.util.findEntityForEditable($editable);
Drupal.edit.entityEditables.startHighlight($e);
}
// Prevent triggering the entity's mouse leave event.
e.stopPropagation();
});
})
- .bind('click.edit', function() {
- Drupal.edit.editables.startEdit($(this)); return false;
+ .each(function() {
+ var editableView = new Drupal.edit.views.EditableView({
+ model: Drupal.edit.util.getElementEntity(jQuery(this), Drupal.edit.vie),
+ el: jQuery(this),
+ predicate: Drupal.edit.util.getElementPredicate(jQuery(this))
+ });
})
// Some transformations are editable-specific.
.map(function() {
@@ -266,17 +199,17 @@ Drupal.edit.startEditableFields = function($fields) {
});
};
-Drupal.edit.stopEditableFields = function($fields) {
- var $editables = Drupal.edit.findEditablesForFields($fields);
+Drupal.edit.stopEditableWidgets = function($fields) {
+ var $editables = Drupal.edit.util.findEditablesForFields($fields);
$fields
.removeClass('edit-processed');
+
+ Drupal.edit.editables.stopEdit($fields);
$editables
.removeClass('edit-candidate edit-editable edit-highlighted edit-editing edit-belowoverlay')
.unbind('mouseenter.edit mouseleave.edit click.edit edit-content-changed.edit')
- .removeAttr('contenteditable')
- .removeData(['edit-content-original', 'edit-content-changed']);
};
Drupal.edit.clickOverlay = function(e) {
@@ -301,7 +234,6 @@ Drupal.edit.clickOverlay = function(e) {
// Entity editables.
Drupal.edit.entityEditables = {
startHighlight: function($editable) {
- return;
console.log('entityEditables.startHighlight');
if (Drupal.edit.toolbar.create($editable)) {
var label = Drupal.t('Edit !entity', { '!entity': $editable.data('edit-entity-label') });
@@ -337,7 +269,6 @@ Drupal.edit.entityEditables = {
},
stopHighlight: function($editable) {
- return;
console.log('entityEditables.stopHighlight');
// Animations.
@@ -353,7 +284,7 @@ Drupal.edit.editables = {
startHighlight: function($editable) {
console.log('editables.startHighlight');
if (Drupal.edit.state.entityBeingHighlighted.length > 0) {
- var $e = Drupal.edit.findEntityForEditable($editable);
+ var $e = Drupal.edit.util.findEntityForEditable($editable);
Drupal.edit.entityEditables.stopHighlight($e);
}
if (Drupal.edit.toolbar.create($editable)) {
@@ -382,7 +313,7 @@ Drupal.edit.editables = {
}, 0);
Drupal.edit.state.fieldBeingHighlighted = $editable;
- Drupal.edit.state.higlightedEditable = Drupal.edit.getID(Drupal.edit.findFieldForEditable($editable));
+ Drupal.edit.state.higlightedEditable = Drupal.edit.util.getID(Drupal.edit.util.findFieldForEditable($editable));
},
stopHighlight: function($editable) {
@@ -399,14 +330,14 @@ Drupal.edit.editables = {
Drupal.edit.state.highlightedEditable = null;
},
- startEdit: function($editable) {
+ startEdit: function($field) {
+ $editable = Drupal.edit.util.findEditablesForFields($field);
if ($editable.hasClass('edit-editing')) {
return;
}
console.log('editables.startEdit: ', $editable);
var self = this;
- var $field = Drupal.edit.findFieldForEditable($editable);
// Highlight if not already highlighted.
if (Drupal.edit.state.fieldBeingHighlighted[0] != $editable[0]) {
@@ -427,7 +358,7 @@ Drupal.edit.editables = {
$('.edit-candidate').not('.edit-editing').removeClass('edit-editable');
// Hide the curtain while editing, the above already prevents comments from
// showing up.
- Drupal.edit.findEntityForField($field).find('.comment-wrapper .edit-curtain').height(0);
+ Drupal.edit.util.findEntityForField($field).find('.comment-wrapper .edit-curtain').height(0);
// Toolbar (already created in the highlight).
Drupal.edit.toolbar.get($editable)
@@ -447,24 +378,22 @@ Drupal.edit.editables = {
return self._buttonFieldCloseClicked(e, $editable, $field);
});
- // Changes to $editable based on the type.
- var callback = ($field.hasClass('edit-type-direct'))
- ? self._updateDirectEditable
- : self._updateFormEditable;
- callback($editable);
+ // Start the editable widget
+ $field.createEditable({disabled: false});
// Regardless of the type, load the form for this field. We always use forms
// to submit the changes.
+ // FIXME: This should be handled by Backbone.sync
self._loadForm($editable, $field);
Drupal.edit.state.fieldBeingEdited = $editable;
- Drupal.edit.state.editedEditable = Drupal.edit.getID($field);
+ Drupal.edit.state.editedEditable = Drupal.edit.util.getID($field);
},
- stopEdit: function($editable) {
+ stopEdit: function($field) {
+ $editable = Drupal.edit.util.findEditablesForFields($field);
console.log('editables.stopEdit: ', $editable);
var self = this;
- var $field = Drupal.edit.findFieldForEditable($editable);
if ($editable.length == 0) {
return;
}
@@ -479,15 +408,12 @@ Drupal.edit.editables = {
// Make the other fields and entities editable again.
$('.edit-candidate').addClass('edit-editable');
// Restore curtain to original height.
- var $curtain = Drupal.edit.findEntityForEditable($editable)
+ var $curtain = Drupal.edit.util.findEntityForEditable($editable)
.find('.comment-wrapper .edit-curtain');
$curtain.height($curtain.data('edit-curtain-height'));
- // Changes to $editable based on the type.
- var callback = ($field.hasClass('edit-type-direct'))
- ? self._restoreDirectEditable
- : self._restoreFormEditable;
- callback($editable);
+ // Start the editable widget
+ $field.createEditable({disabled: true});
Drupal.edit.toolbar.remove($editable);
Drupal.edit.form.remove($editable);
@@ -500,7 +426,7 @@ Drupal.edit.editables = {
// Indicate in the 'info' toolgroup that the form is loading.
Drupal.edit.toolbar.addClass($editable, 'primary', 'info', 'loading');
- var edit_id = Drupal.edit.getID($field);
+ var edit_id = Drupal.edit.util.getID($field);
var element_settings = {
url : Drupal.edit.util.calcRerenderProcessedTextURL(edit_id),
event : 'edit-internal-load-rerender.edit',
@@ -520,16 +446,14 @@ Drupal.edit.editables = {
// Attach, activate and show the WYSIWYG editor.
_wysiwygify: function($editable) {
$editable.addClass('edit-wysiwyg-attached');
- Drupal.edit.wysiwyg[Drupal.settings.edit.wysiwyg].attach($editable);
- Drupal.edit.wysiwyg[Drupal.settings.edit.wysiwyg].activate($editable);
Drupal.edit.toolbar.show($editable, 'secondary', 'wysiwyg-tabs');
Drupal.edit.toolbar.show($editable, 'tertiary', 'wysiwyg');
},
- _updateDirectEditable: function($editable) {
+ _updateDirectEditable: function($field) {
+ $editable = Drupal.edit.util.findEditablesForFields($field);
Drupal.edit.editables._padEditable($editable);
- var $field = Drupal.edit.findFieldForEditable($editable);
if ($field.hasClass('edit-type-direct-with-wysiwyg')) {
Drupal.edit.toolbar.get($editable)
.find('.edit-toolbar.secondary:not(:has(.edit-toolgroup.wysiwyg-tabs))')
@@ -549,8 +473,6 @@ Drupal.edit.editables = {
// it without the transformation filters.
if ($field.hasClass('edit-text-with-transformation-filters')) {
Drupal.edit.editables._loadRerenderedProcessedText($editable, $field);
- // Also store the "real" original content, i.e. the transformed one.
- $editable.data('edit-content-original-transformed', $editable.html())
}
// When no transformation filters have been applied: start WYSIWYG editing
// immediately!
@@ -560,70 +482,27 @@ Drupal.edit.editables = {
}, 0);
}
}
- else {
- $editable.attr('contenteditable', true);
- }
$editable
- .data('edit-content-original', $editable.html())
.data('edit-content-changed', false);
- // Detect content changes ourselves only when not using a WYSIWYG editor.
- var markContentChanged = function() {
+ $field.bind('createeditablechanged', function() {
$editable.data('edit-content-changed', true);
$editable.trigger('edit-content-changed.edit');
- };
- if (!$field.hasClass('edit-type-direct-with-wysiwyg')) {
- // We cannot use Drupal.behaviors.formUpdated here because we're not dealing
- // with a form!
- $editable
- .bind('blur.edit keyup.edit paste.edit', function() {
- if ($editable.html() != $editable.data('edit-content-original')) {
- markContentChanged();
- }
- })
- // Disallow return/enter key when editing titles.
- .bind('keypress.edit', function(event) {
- if (event.keyCode == 13) {
- return false;
- }
- });
- }
- else {
- $editable.bind('edit-wysiwyg-content-changed.edit', function() {
- markContentChanged();
- });
- }
+ });
},
- _restoreDirectEditable: function($editable) {
- if (Drupal.edit.findFieldForEditable($editable).hasClass('edit-type-direct-with-wysiwyg')
+ _restoreDirectEditable: function($field) {
+ $editable = Drupal.edit.util.findEditablesForFields($field);
+ if (Drupal.edit.util.findFieldForEditable($editable).hasClass('edit-type-direct-with-wysiwyg')
&& $editable.hasClass('edit-wysiwyg-attached'))
{
$editable.removeClass('edit-wysiwyg-attached');
- Drupal.edit.wysiwyg[Drupal.settings.edit.wysiwyg].detach($editable);
-
- // Work-around for major AE bug. See:
- // - http://drupal.org/node/1725032
- // - https://github.com/alohaeditor/Aloha-Editor/issues/693.
- // Also unbind to make sure this doesn't break anything when using
- // this version of edit.js with a fixed version of Aloha Editor.
- $editable
- .unbind('click.edit')
- .bind('click.edit', function() {
- Drupal.edit.editables.startEdit($(this)); return false;
- });
- }
- else {
- $editable
- .removeAttr('contenteditable')
- .unbind('keypress.edit');
}
Drupal.edit.editables._unpadEditable($editable);
$editable
- .removeData(['edit-content-original', 'edit-content-changed', 'edit-content-original-transformed'])
.unbind('blur.edit keyup.edit paste.edit edit-content-changed.edit');
// Not only clean up the changes to $editable, but also clean up the
@@ -744,28 +623,8 @@ Drupal.edit.editables = {
}, 0);
},
- // Creates a form container; when the $editable is inline, it will inherit CSS
- // properties from the toolbar container, so the toolbar must already exist.
- _updateFormEditable: function($editable) {
- if (Drupal.edit.form.create($editable)) {
- $editable
- .addClass('edit-belowoverlay')
- .removeClass('edit-highlighted edit-editable');
-
- Drupal.edit.form.get($editable)
- .find('.edit-form')
- .addClass('edit-editable edit-highlighted edit-editing')
- .css('background-color', $editable.data('edit-background-color'));
- }
- },
-
- _restoreFormEditable: function($editable) {
- // No need to do anything here; all of the field HTML will be overwritten
- // with the freshly rendered version from the server anyway!
- },
-
_loadForm: function($editable, $field) {
- var edit_id = Drupal.edit.getID($field);
+ var edit_id = Drupal.edit.util.getID($field);
var element_settings = {
url : Drupal.edit.util.calcFormURLForField(edit_id),
event : 'edit-internal.edit',
@@ -797,25 +656,13 @@ Drupal.edit.editables = {
else if ($field.hasClass('edit-type-direct')) {
$editable.blur();
- var wysiwyg = $field.hasClass('edit-type-direct-with-wysiwyg')
- && $editable.hasClass('edit-wysiwyg-attached');
+ var entity = Drupal.edit.util.getElementEntity($field, Drupal.edit.vie);
+ var value = entity.get(Drupal.edit.util.getElementPredicate($editable));
- // When using WYSIWYG editing, first detach the WYSIWYG editor to ensure
- // the content has been cleaned up before saving it. (Otherwise,
- // annotations and infrastructure created by the WYSIWYG editor could also
- // get saved).
- if (wysiwyg) {
- $editable.removeClass('edit-wysiwyg-attached');
- Drupal.edit.wysiwyg[Drupal.settings.edit.wysiwyg].detach($editable);
- }
+ // TODO: Use Backbone.sync so we can support the Drupal 8 API
+ // without code changes in Spark
+ // entity.save();
- // We trim the title because otherwise whitespace in the raw HTML ends
- // up in the title as well.
- // TRICKY: Drupal core does not trim the title, so in theory this is
- // out of line with Drupal core's behavior.
- var value = (wysiwyg)
- ? $.trim($editable.html())
- : $.trim($editable.text());
$('#edit_backstage form')
.find(':input[type!="hidden"][type!="submit"]').val(value).end()
.find('.edit-form-submit').trigger('click.edit');
@@ -824,20 +671,12 @@ Drupal.edit.editables = {
},
_buttonFieldCloseClicked: function(e, $editable, $field) {
- // Content not changed: stop editing field.
- if (!$editable.data('edit-content-changed')) {
- // Restore to original content. When dealing with processed text, it's
- // possible that one or more transformation filters are used. Then, the
- // "real" original content (i.e. the transformed one) is stored separately
- // from the "original content" that we use to detect changes.
- if (typeof $editable.data('edit-content-original-transformed') !== 'undefined') {
- $editable.html($editable.data('edit-content-original-transformed'));
- }
-
- Drupal.edit.editables.stopEdit($editable);
- }
- // Content changed: show modal.
- else {
+ if (!Drupal.edit.util.getElementEntity($field, Drupal.edit.vie).hasChanged()) {
+ // Content not changed: stop editing field.
+ // The view will restore contents automatically when we disable editor
+ Drupal.edit.editables.stopEdit($field);
+ } else {
+ // Content changed: show modal.
Drupal.edit.modal.create(
Drupal.t('You have unsaved changes'),
Drupal.theme('editButtons', { 'buttons' : [
diff --git a/js/editable.js b/js/editable.js
new file mode 100644
index 0000000..173feac
--- /dev/null
+++ b/js/editable.js
@@ -0,0 +1,47 @@
+(function (jQuery, undefined) {
+ // # Create.js editing widget for Spark
+ //
+ // This widget inherits from the Create.js editable widget to accommodate
+ // for the fact that Spark is using custom data attributes and not RDFa
+ // to communicate editable fields.
+ jQuery.widget('Drupal.createEditable', jQuery.Midgard.midgardEditable, {
+ _create: function () {
+ this.vie = this.options.vie;
+
+ this.options.editors.direct = {
+ widget: 'editWidget',
+ options: {}
+ };
+ this.options.editors.directWysiwyg = {
+ widget: 'alohaWidget',
+ options: {}
+ };
+ this.options.editors.form = {
+ widget: 'drupalFormWidget',
+ options: {}
+ };
+ },
+
+ findEditableElements: function (callback) {
+ var model = this.options.model;
+ var fields = Drupal.edit.util.findEditableFields(this.element).andSelf().filter(function () {
+ return Drupal.edit.util.getElementSubject(jQuery(this)) == model.getSubjectUri();
+ });
+ Drupal.edit.util.findEditablesForFields(fields).each(callback);
+ },
+
+ getElementPredicate: function (element) {
+ return Drupal.edit.util.getElementPredicate(jQuery(element));
+ },
+
+ _editorName: function (data) {
+ if (Drupal.settings.edit.wysiwyg && jQuery(this.element).hasClass('edit-type-direct')) {
+ if (jQuery(this.element).hasClass('edit-type-direct-with-wysiwyg')) {
+ return 'directWysiwyg';
+ }
+ return 'direct';
+ }
+ return 'form';
+ }
+ });
+})(jQuery);
diff --git a/js/formwidget.js b/js/formwidget.js
new file mode 100644
index 0000000..3586e05
--- /dev/null
+++ b/js/formwidget.js
@@ -0,0 +1,47 @@
+(function (jQuery, undefined) {
+ // # Drupal form-based editing widget for Create.js
+ jQuery.widget('Drupal.drupalFormWidget', jQuery.Create.editWidget, {
+ options: {
+ editorOptions: {},
+ disabled: true
+ },
+
+ enable: function () {
+ this.options.disabled = false;
+ this.loadForm();
+ },
+
+ loadForm: function () {
+ if (Drupal.edit.form.create(this.element)) {
+ this.element
+ .addClass('edit-belowoverlay')
+ .removeClass('edit-highlighted edit-editable');
+
+ Drupal.edit.form.get(this.element)
+ .find('.edit-form')
+ .addClass('edit-editable edit-highlighted edit-editing')
+ .css('background-color', this.element.data('edit-background-color'));
+ }
+
+ var field = Drupal.edit.util.findFieldForEditable(this.element);
+ //Drupal.edit.editables._loadForm(this.element, field);
+ },
+
+ disable: function () {
+ this.options.disabled = true;
+
+ Drupal.edit.form.get(this.element).remove();
+ },
+
+ _initialize: function () {
+ var self = this;
+ jQuery(this.element).bind('focus', function (event) {
+ self.options.activated();
+ });
+
+ jQuery(this.element).bind('blur', function (event) {
+ self.options.deactivated();
+ });
+ }
+ });
+})(jQuery);
diff --git a/js/ui-editables.js b/js/ui-editables.js
index ac14cd0..21f15f8 100644
--- a/js/ui-editables.js
+++ b/js/ui-editables.js
@@ -134,9 +134,7 @@ Drupal.edit.toolbar = {
},
_id: function($editable) {
- var edit_id = ($editable.hasClass('edit-entity'))
- ? Drupal.edit.getID($editable)
- : Drupal.edit.getID(Drupal.edit.findFieldForEditable($editable));
+ var edit_id = Drupal.edit.util.getID($editable);
return 'edit-toolbar-for-' + edit_id.split(':').join('_');
}
};
@@ -190,9 +188,7 @@ Drupal.edit.form = {
},
_id: function($editable) {
- var edit_id = ($editable.hasClass('edit-entity'))
- ? Drupal.edit.getID($editable)
- : Drupal.edit.getID(Drupal.edit.findFieldForEditable($editable));
+ var edit_id = Drupal.edit.util.getID($editable);
return 'edit-form-for-' + edit_id.split(':').join('_');
}
};
diff --git a/js/util.js b/js/util.js
index 32ba314..6141dd6 100644
--- a/js/util.js
+++ b/js/util.js
@@ -8,6 +8,112 @@
Drupal.edit = Drupal.edit || {};
Drupal.edit.util = Drupal.edit.util || {};
+Drupal.edit.util.views = {};
+
+Drupal.edit.util.getID = function(element) {
+ var id = jQuery(element).data('edit-id');
+ if (!id) {
+ id = jQuery(element).closest('[data-edit-id]').data('edit-id');
+ }
+ return id;
+};
+
+Drupal.edit.util.getElementSubject = function(element) {
+ return Drupal.edit.util.getID(element).split(':').slice(0, 2).join(':');
+};
+
+Drupal.edit.util.getElementPredicate = function(element) {
+ return Drupal.edit.util.getID(element).split(':').pop();
+};
+
+Drupal.edit.util.getElementValue = function(element) {
+ var valueElement = jQuery('.field-item', element);
+ if (valueElement.length === 0) {
+ // Handle page title
+ valueElement = jQuery('h1', element);
+ }
+ return $.trim(valueElement.html());
+};
+
+Drupal.edit.util.getElementEntity = function(element, vie) {
+ return vie.entities.get(Drupal.edit.util.getElementSubject(element));
+};
+
+Drupal.edit.util.findEditableEntities = function(context) {
+ var entityElements = $('.edit-entity.edit-allowed', context || Drupal.settings.edit.context);
+ entityElements.each(function () {
+ // Register the entity with VIE
+ Drupal.edit.vie.entities.addOrUpdate({
+ '@subject': Drupal.edit.util.getElementSubject(jQuery(this)),
+ '@type': jQuery(this).data('edit-entity-label')
+ }, {
+ overrideAttributes: true
+ });
+ });
+ return entityElements;
+};
+
+Drupal.edit.util.findEditableFields = function(context) {
+ var propertyElements = $('.edit-field.edit-allowed', context || Drupal.settings.edit.context);
+ propertyElements.each(function () {
+ // Register with VIE
+ var propertyName = Drupal.edit.util.getElementPredicate(jQuery(this));
+ var entityData = {
+ '@subject': Drupal.edit.util.getElementSubject(jQuery(this))
+ };
+ entityData[propertyName] = Drupal.edit.util.getElementValue(jQuery(this));
+ Drupal.edit.vie.entities.addOrUpdate(entityData, {
+ overrideAttributes: true
+ });
+ });
+ return propertyElements;
+};
+
+/*
+ * findEditableFields() just looks for fields that are editable, i.e. for the
+ * field *wrappers*. Depending on the field, however, either the whole field wrapper
+ * will be marked as editable (in this case, an inline form will be used for editing),
+ * *or* a specific (field-specific even!) DOM element within that field wrapper will be
+ * marked as editable.
+ * This function is for finding the *editables* themselves, given the *editable fields*.
+ */
+Drupal.edit.util.findEditablesForFields = function($fields) {
+ var $editables = $();
+
+ // type = form
+ $editables = $editables.add($fields.filter('.edit-type-form'));
+
+ // type = direct
+ var $direct = $fields.filter('.edit-type-direct');
+ $editables = $editables.add($direct.find('.field-item'));
+ // Edge case: "title" pseudofield on pages with lists of nodes.
+ $editables = $editables.add($direct.filter('h2').find('a'));
+ // Edge case: "title" pseudofield on node pages.
+ $editables = $editables.add($direct.find('h1'));
+
+ return $editables;
+};
+
+Drupal.edit.util.findFieldForID = function(id, context) {
+ return $('[data-edit-id="' + id + '"]', context || $('#content'));
+};
+
+Drupal.edit.util.findFieldForEditable = function($editable) {
+ return $editable.filter('.edit-type-form').length ? $editable : $editable.closest('.edit-type-direct');
+};
+
+Drupal.edit.util.findEntityForEditable = function($editable) {
+ return Drupal.edit.util.findEntityForField(Drupal.edit.util.findFieldForEditable($editable));
+};
+
+Drupal.edit.util.findEntityForField = function($f) {
+ var $e = $f.closest('.edit-entity');
+ if ($e.length == 0) {
+ var entity_edit_id = $f.data('edit-id').split(':').slice(0,2).join(':');
+ $e = $('.edit-entity[data-edit-id="' + entity_edit_id + '"]');
+ }
+ return $e;
+};
Drupal.edit.util.calcFormURLForField = function(id) {
var parts = id.split(':');
diff --git a/js/views.js b/js/views.js
new file mode 100644
index 0000000..979cc70
--- /dev/null
+++ b/js/views.js
@@ -0,0 +1,17 @@
+(function ($) {
+ Drupal.edit = Drupal.edit || {};
+ Drupal.edit.views = Drupal.edit.views || {};
+
+ Drupal.edit.views.EditableView = Backbone.View.extend({
+ predicate: null,
+ initialize: function (options) {
+ this.predicate = '<http://viejs.org/ns/' + options.predicate + '>';
+ _.bindAll(this, 'render');
+ this.model.bind('change:' + this.predicate, this.render);
+ },
+
+ render: function () {
+ jQuery(this.el).html(this.model.get(this.predicate));
+ }
+ });
+})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment