-
-
Notifications
You must be signed in to change notification settings - Fork 366
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #941 from userfrosting/develop-ufModelArch
ufModel architecture update
- Loading branch information
Showing
1 changed file
with
115 additions
and
152 deletions.
There are no files selected for viewing
267 changes: 115 additions & 152 deletions
267
app/sprinkles/core/assets/userfrosting/js/uf-modal.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,192 +1,155 @@ | ||
/// <reference types="jquery" /> | ||
/** | ||
* ufModal plugin. Handles modal windows that dynamically their fetch content from a specified URL. | ||
* | ||
* | ||
* UserFrosting https://www.userfrosting.com | ||
* @author Alexander Weissman https://alexanderweissman.com | ||
* @author Alexander Weissman <https://alexanderweissman.com> | ||
*/ | ||
(function( $ ) | ||
{ | ||
;(function($, document, undefined) { | ||
'use strict'; | ||
|
||
// Define plugin name and defaults. | ||
var pluginName = 'ufModal'; | ||
/** | ||
* The plugin namespace, ie for $('.selector').ufModal(options) | ||
* | ||
* Also the id for storing the object state via $('.selector').data() | ||
* @typedef {{ | ||
* sourceUrl: string, | ||
* ajaxParams: JQuery.PlainObject | string, | ||
* msgTarget?: JQuery<HTMLElement>|null | ||
* DEBUG?: boolean, | ||
* }} Options | ||
* @type {Options} | ||
*/ | ||
var PLUGIN_NS = 'ufModal'; | ||
|
||
var Plugin = function ( target, options ) | ||
{ | ||
var defaults = { | ||
sourceUrl : '', | ||
ajaxParams: {}, | ||
msgTarget : null, | ||
DEBUG : false | ||
}; | ||
|
||
this.$T = $(target); | ||
/** | ||
* @param {ArrayLike<HTMLElement>} inElement | ||
* @param {Options|undefined} options | ||
*/ | ||
function createPlugin(inElement, options) { | ||
var element = inElement[0]; | ||
var $element = $(element); | ||
var settings = $.extend(true, defaults, options); | ||
|
||
/** #### OPTIONS #### */ | ||
this.options= $.extend( | ||
true, // deep extend | ||
{ | ||
sourceUrl : "", | ||
ajaxParams: {}, | ||
msgTarget : null, | ||
DEBUG: false | ||
}, | ||
options | ||
); | ||
// True plugin initialization commences | ||
/** @type {JQuery<HTMLElement>|null} */ | ||
var modal = null; | ||
|
||
this.modal = null; | ||
// Delete any existing modals attached to the element (should have been deleted already anyway) | ||
if ($element.find('.modal').length) $element.find('.modal').remove(); | ||
|
||
this._init( target ); | ||
function destroy() { | ||
// Remove modal from selector | ||
if (modal) modal.remove(); | ||
|
||
return this; | ||
}; | ||
// Unbind plugin events | ||
$element.off('.' + pluginName); | ||
|
||
/** #### INITIALIZER #### */ | ||
Plugin.prototype._init = function ( target ) | ||
{ | ||
var base = this; | ||
var $el = $(target); | ||
// Remove plugin data from internal jQuery store (jQuery doesn't store with data-*, but can access it) | ||
$element.removeData(pluginName); | ||
|
||
// Delete any existing modals attached to the element (should have been deleted already anyway) | ||
if ($el.find(".modal").length) { | ||
$el.find(".modal").remove(); | ||
return $element; | ||
} | ||
|
||
// Fetch and render the form | ||
// Fetch and render | ||
$.ajax({ | ||
type: "GET", | ||
url: base.options.sourceUrl, | ||
data: base.options.ajaxParams, | ||
cache: false | ||
}) | ||
.then( | ||
// Fetch successful | ||
type: 'GET', | ||
url: settings.sourceUrl, | ||
data: settings.ajaxParams, | ||
cache: false, | ||
}).then( | ||
// Success | ||
function (data) { | ||
// Append the form as a modal dialog to the body | ||
base.modal = $(data); | ||
$el.append(base.modal); | ||
// Append the data as a modal dialog to the target element | ||
modal = $(data); | ||
$element.append(modal); | ||
|
||
base.modal.modal('show'); | ||
// Trigger modal dialog | ||
modal.modal('show'); | ||
|
||
// Bind modal to be deleted when closed | ||
base.modal.on("hidden.bs.modal", function () { | ||
base.destroy(); | ||
}); | ||
// Bind destroy function to close event | ||
modal.on('hidden.bs.modal', function () { destroy(); }); | ||
|
||
base.$T.trigger('renderSuccess.ufModal'); | ||
return data; | ||
// Trigger success event | ||
$element.trigger('renderSuccess.ufModal'); | ||
}, | ||
// Fetch failed | ||
// Failure | ||
function (data) { | ||
// Error messages | ||
if ((typeof site !== "undefined") && site.debug.ajax && data.responseText) { | ||
base.$T.trigger('renderError.ufModal'); | ||
// Handle error messages | ||
if (site !== undefined && site.debug.ajax && data.responseText) { | ||
// Trigger failure event | ||
$element.trigger('renderError.ufModal'); | ||
|
||
// Replace document content with response, and handle browser quirks | ||
document.write(data.responseText); | ||
document.close(); | ||
} else { | ||
if (base.options.DEBUG) { | ||
console.log("Error (" + data.status + "): " + data.responseText ); | ||
} | ||
// Display errors on failure | ||
// TODO: ufAlerts widget should have a 'destroy' method | ||
if (!base.options.msgTarget.data('ufAlerts')) { | ||
base.options.msgTarget.ufAlerts(); | ||
// Debug logging | ||
if (settings.DEBUG) console.log('Error (' + data.status + '): ' + data.responseText); | ||
|
||
// Refresh ufAlerts for errors if target defined | ||
if (settings.msgTarget) { | ||
// Check if ufAlerts is instanced and empty | ||
if (!settings.msgTarget.data('ufAlerts')) settings.msgTarget.ufAlerts(); | ||
else settings.msgTarget.ufAlerts('clear'); | ||
|
||
// Trigger failure event on render.ufAlerts event | ||
settings.msgTarget.on('render.ufAlerts', function () { | ||
$element.trigger('renderError.ufModal'); | ||
}); | ||
|
||
// Pull alerts | ||
settings.msgTarget.ufAlerts('fetch').ufAlerts('render'); | ||
} else { | ||
base.options.msgTarget.ufAlerts('clear'); | ||
// renderError.ufModal event should always be able to trigger | ||
$element.trigger('renderError.ufModal'); | ||
} | ||
|
||
base.options.msgTarget.ufAlerts('fetch').ufAlerts('render'); | ||
base.options.msgTarget.on("render.ufAlerts", function () { | ||
base.$T.trigger('renderError.ufModal'); | ||
}); | ||
} | ||
|
||
base.destroy(); | ||
|
||
return data; | ||
} | ||
); | ||
}; | ||
|
||
Plugin.prototype.destroy = function () { | ||
var base = this; | ||
var $el = base.$T; | ||
) | ||
|
||
// Delete the plugin object | ||
base.delete; | ||
|
||
// Remove the modal from the selector | ||
if (base.modal) { | ||
base.modal.remove(); | ||
/** | ||
* Returns underlying modal | ||
*/ | ||
function getModal() { | ||
return modal; | ||
} | ||
|
||
// Unbind any modal events bound to the selector | ||
$el.off('.ufModal'); | ||
|
||
// Remove plugin name from selector's data-* attribute | ||
$el.removeData(PLUGIN_NS); | ||
}; | ||
|
||
Plugin.prototype.getModal = function () { | ||
return this.modal; | ||
}; | ||
|
||
/** | ||
* EZ Logging/Warning (technically private but saving an '_' is worth it imo) | ||
*/ | ||
Plugin.prototype.DLOG = function () | ||
{ | ||
if (!this.DEBUG) return; | ||
for (var i in arguments) { | ||
console.log( PLUGIN_NS + ': ', arguments[i] ); | ||
} | ||
} | ||
Plugin.prototype.DWARN = function () | ||
{ | ||
this.DEBUG && console.warn( arguments ); | ||
return { | ||
destroy, | ||
getModal, | ||
}; | ||
} | ||
|
||
|
||
/*################################################################################### | ||
* JQUERY HOOK | ||
###################################################################################*/ | ||
|
||
/** | ||
* Generic jQuery plugin instantiation method call logic | ||
* | ||
* Method options are stored via jQuery's data() method in the relevant element(s) | ||
* Notice, myActionMethod mustn't start with an underscore (_) as this is used to | ||
* indicate private methods on the PLUGIN class. | ||
* Handles instantiation and access to non-private methods. | ||
* @param {Options|keyof ReturnType<createPlugin>|undefined} methodOrOptions | ||
*/ | ||
$.fn[ PLUGIN_NS ] = function( methodOrOptions ) | ||
{ | ||
if (!$(this).length) { | ||
return $(this); | ||
function interop(methodOrOptions) { | ||
// Grab plugin instance | ||
/** @type {ReturnType<createPlugin>|undefined} */ | ||
var instance = $(this).data(pluginName); | ||
|
||
// If undefined or object, initialize plugin. | ||
if (typeof methodOrOptions === 'undefined' || typeof methodOrOptions === 'object') { | ||
// Only initialize if not previously done. | ||
if (!instance) { | ||
$(this).data(pluginName, createPlugin(this, methodOrOptions)); | ||
} | ||
return this; | ||
} | ||
var instance = $(this).data(PLUGIN_NS); | ||
|
||
// CASE: action method (public method on PLUGIN class) | ||
if ( instance | ||
&& methodOrOptions.indexOf('_') != 0 | ||
&& instance[ methodOrOptions ] | ||
&& typeof( instance[ methodOrOptions ] ) == 'function' ) { | ||
|
||
return instance[ methodOrOptions ]( Array.prototype.slice.call( arguments, 1 ) ); | ||
|
||
|
||
// CASE: argument is options object or empty = initialize | ||
} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { | ||
|
||
instance = new Plugin( $(this), methodOrOptions ); // ok to overwrite if this is a re-init | ||
$(this).data( PLUGIN_NS, instance ); | ||
return $(this); | ||
|
||
// CASE: method called before init | ||
} else if ( !instance ) { | ||
console.warn( 'Plugin must be initialized before using method: ' + methodOrOptions ); | ||
|
||
// CASE: invalid method | ||
} else if ( methodOrOptions.indexOf('_') == 0 ) { | ||
console.warn( 'Method ' + methodOrOptions + ' is private!' ); | ||
} else { | ||
console.warn( 'Method ' + methodOrOptions + ' does not exist.' ); | ||
// Otherwise ensure first parameter is a valid string, and is the name of an actual function. | ||
else if (typeof methodOrOptions === 'string' && typeof instance[methodOrOptions] === 'function') { | ||
return instance[methodOrOptions](); | ||
} | ||
else { | ||
console.error('Method ' + methodOrOptions + ' does not exist.'); | ||
} | ||
}; | ||
})(jQuery); | ||
|
||
$.fn[pluginName] = interop; | ||
})(jQuery, document); |