You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
7.7 KiB
245 lines
7.7 KiB
/** |
|
* Yii JavaScript module. |
|
* |
|
* @link http://www.yiiframework.com/ |
|
* @copyright Copyright (c) 2008 Yii Software LLC |
|
* @license http://www.yiiframework.com/license/ |
|
* @author Qiang Xue <qiang.xue@gmail.com> |
|
* @since 2.0 |
|
*/ |
|
|
|
/** |
|
* yii is the root module for all Yii JavaScript modules. |
|
* It implements a mechanism of organizing JavaScript code in modules through the function "yii.initModule()". |
|
* |
|
* Each module should be named as "x.y.z", where "x" stands for the root module (for the Yii core code, this is "yii"). |
|
* |
|
* A module may be structured as follows: |
|
* |
|
* ~~~ |
|
* yii.sample = (function($) { |
|
* var pub = { |
|
* // whether this module is currently active. If false, init() will not be called for this module |
|
* // it will also not be called for all its child modules. If this property is undefined, it means true. |
|
* isActive: true, |
|
* init: function() { |
|
* // ... module initialization code go here ... |
|
* }, |
|
* |
|
* // ... other public functions and properties go here ... |
|
* }; |
|
* |
|
* // ... private functions and properties go here ... |
|
* |
|
* return pub; |
|
* })(jQuery); |
|
* ~~~ |
|
* |
|
* Using this structure, you can define public and private functions/properties for a module. |
|
* Private functions/properties are only visible within the module, while public functions/properties |
|
* may be accessed outside of the module. For example, you can access "yii.sample.isActive". |
|
* |
|
* You must call "yii.initModule()" once for the root module of all your modules. |
|
*/ |
|
yii = (function ($) { |
|
var pub = { |
|
/** |
|
* List of scripts that can be loaded multiple times via AJAX requests. Each script can be represented |
|
* as either an absolute URL or a relative one. |
|
*/ |
|
reloadableScripts: [], |
|
/** |
|
* The selector for clickable elements that need to support confirmation and form submission. |
|
*/ |
|
clickableSelector: 'a, button, input[type="submit"], input[type="button"], input[type="reset"], input[type="image"]', |
|
/** |
|
* The selector for changeable elements that need to support confirmation and form submission. |
|
*/ |
|
changeableSelector: 'select, input, textarea', |
|
|
|
/** |
|
* @return string|undefined the CSRF variable name. Undefined is returned if CSRF validation is not enabled. |
|
*/ |
|
getCsrfVar: function () { |
|
return $('meta[name=csrf-var]').prop('content'); |
|
}, |
|
|
|
/** |
|
* @return string|undefined the CSRF token. Undefined is returned if CSRF validation is not enabled. |
|
*/ |
|
getCsrfToken: function () { |
|
return $('meta[name=csrf-token]').prop('content'); |
|
}, |
|
|
|
/** |
|
* Displays a confirmation dialog. |
|
* The default implementation simply displays a js confirmation dialog. |
|
* You may override this by setting `yii.confirm`. |
|
* @param message the confirmation message. |
|
* @return boolean whether the user confirms with the message in the dialog |
|
*/ |
|
confirm: function (message) { |
|
return confirm(message); |
|
}, |
|
|
|
/** |
|
* Returns a value indicating whether to allow executing the action defined for the specified element. |
|
* This method recognizes the `data-confirm` attribute of the element and uses it |
|
* as the message in a confirmation dialog. The method will return true if this special attribute |
|
* is not defined or if the user confirms the message. |
|
* @param $e the jQuery representation of the element |
|
* @return boolean whether to allow executing the action defined for the specified element. |
|
*/ |
|
allowAction: function ($e) { |
|
var message = $e.data('confirm'); |
|
return message === undefined || pub.confirm(message); |
|
}, |
|
|
|
/** |
|
* Handles the action triggered by user. |
|
* This method recognizes the `data-method` attribute of the element. If the attribute exists, |
|
* the method will submit the form containing this element. If there is no containing form, a form |
|
* will be created and submitted using the method given by this attribute value (e.g. "post", "put"). |
|
* For hyperlinks, the form action will take the value of the "href" attribute of the link. |
|
* For other elements, either the containing form action or the current page URL will be used |
|
* as the form action URL. |
|
* |
|
* If the `data-method` attribute is not defined, the default element action will be performed. |
|
* |
|
* @param $e the jQuery representation of the element |
|
* @return boolean whether to execute the default action for the element. |
|
*/ |
|
handleAction: function ($e) { |
|
var method = $e.data('method'); |
|
if (method === undefined) { |
|
return true; |
|
} |
|
|
|
var $form = $e.closest('form'); |
|
var newForm = !$form.length; |
|
if (newForm) { |
|
var action = $e.prop('href'); |
|
if (!action || !action.match(/(^\/|:\/\/)/)) { |
|
action = window.location.href; |
|
} |
|
$form = $('<form method="' + method + '" action="' + action + '"></form>'); |
|
var target = $e.prop('target'); |
|
if (target) { |
|
$form.attr('target', target); |
|
} |
|
if (!method.match(/(get|post)/i)) { |
|
$form.append('<input name="_method" value="' + method + '" type="hidden">'); |
|
} |
|
var csrfVar = pub.getCsrfVar(); |
|
if (csrfVar) { |
|
$form.append('<input name="' + csrfVar + '" value="' + pub.getCsrfToken() + '" type="hidden">'); |
|
} |
|
$form.hide().appendTo('body'); |
|
} |
|
|
|
var activeFormData = $form.data('yiiActiveForm'); |
|
if (activeFormData) { |
|
// remember who triggers the form submission. This is used by yii.activeForm.js |
|
activeFormData.submitObject = $e; |
|
} |
|
|
|
$form.trigger('submit'); |
|
|
|
if (newForm) { |
|
$form.remove(); |
|
} |
|
|
|
return false; |
|
}, |
|
|
|
initModule: function (module) { |
|
if (module.isActive === undefined || module.isActive) { |
|
if ($.isFunction(module.init)) { |
|
module.init(); |
|
} |
|
$.each(module, function () { |
|
if ($.isPlainObject(this)) { |
|
pub.initModule(this); |
|
} |
|
}); |
|
} |
|
}, |
|
|
|
init: function () { |
|
initCsrfHandler(); |
|
initRedirectHandler(); |
|
initScriptFilter(); |
|
initDataMethods(); |
|
} |
|
}; |
|
|
|
function initRedirectHandler() { |
|
// handle AJAX redirection |
|
$(document).ajaxComplete(function (event, xhr, settings) { |
|
var url = xhr.getResponseHeader('X-Redirect'); |
|
if (url) { |
|
window.location = url; |
|
} |
|
}); |
|
} |
|
|
|
function initCsrfHandler() { |
|
// automatically send CSRF token for all AJAX requests |
|
$.ajaxPrefilter(function (options, originalOptions, xhr) { |
|
if (!options.crossDomain && pub.getCsrfVar()) { |
|
xhr.setRequestHeader('X-CSRF-Token', pub.getCsrfToken()); |
|
} |
|
}); |
|
} |
|
|
|
function initDataMethods() { |
|
var $document = $(document); |
|
// handle data-confirm and data-method for clickable elements |
|
$document.on('click.yii', pub.clickableSelector, function (event) { |
|
var $this = $(this); |
|
if (pub.allowAction($this)) { |
|
return pub.handleAction($this); |
|
} else { |
|
event.stopImmediatePropagation(); |
|
return false; |
|
} |
|
}); |
|
|
|
// handle data-confirm and data-method for changeable elements |
|
$document.on('change.yii', pub.changeableSelector, function (event) { |
|
var $this = $(this); |
|
if (pub.allowAction($this)) { |
|
return pub.handleAction($this); |
|
} else { |
|
event.stopImmediatePropagation(); |
|
return false; |
|
} |
|
}); |
|
} |
|
|
|
function initScriptFilter() { |
|
var hostInfo = location.protocol + '//' + location.host; |
|
var loadedScripts = $('script[src]').map(function () { |
|
return this.src.charAt(0) === '/' ? hostInfo + this.src : this.src; |
|
}).toArray(); |
|
$.ajaxPrefilter('script', function (options, originalOptions, xhr) { |
|
var url = options.url.charAt(0) === '/' ? hostInfo + options.url : options.url; |
|
if ($.inArray(url, loadedScripts) === -1) { |
|
loadedScripts.push(url); |
|
} else { |
|
var found = $.inArray(url, $.map(pub.reloadableScripts, function (script) { |
|
return script.charAt(0) === '/' ? hostInfo + script : script; |
|
})) !== -1; |
|
if (!found) { |
|
xhr.abort(); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
return pub; |
|
})(jQuery); |
|
|
|
jQuery(document).ready(function () { |
|
yii.initModule(yii); |
|
});
|
|
|