1/** 2 * Yii JavaScript module. 3 * 4 * @link http://www.yiiframework.com/ 5 * @copyright Copyright (c) 2008 Yii Software LLC 6 * @license http://www.yiiframework.com/license/ 7 * @author Qiang Xue <[email protected]> 8 * @since 2.0 9 */ 10 11/** 12 * yii is the root module for all Yii JavaScript modules. 13 * It implements a mechanism of organizing JavaScript code in modules through the function "yii.initModule()". 14 * 15 * Each module should be named as "x.y.z", where "x" stands for the root module (for the Yii core code, this is "yii"). 16 * 17 * A module may be structured as follows: 18 * 19 * ~~~ 20 * yii.sample = (function($) { 21 * var pub = { 22 * // whether this module is currently active. If false, init() will not be called for this module 23 * // it will also not be called for all its child modules. If this property is undefined, it means true. 24 * isActive: true, 25 * init: function() { 26 * // ... module initialization code go here ... 27 * }, 28 * 29 * // ... other public functions and properties go here ... 30 * }; 31 * 32 * // ... private functions and properties go here ... 33 * 34 * return pub; 35 * })(jQuery); 36 * ~~~ 37 * 38 * Using this structure, you can define public and private functions/properties for a module. 39 * Private functions/properties are only visible within the module, while public functions/properties 40 * may be accessed outside of the module. For example, you can access "yii.sample.isActive". 41 * 42 * You must call "yii.initModule()" once for the root module of all your modules. 43 */ 44yii = (function ($) { 45 var pub = { 46 /** 47 * List of JS or CSS URLs that can be loaded multiple times via AJAX requests. Each script can be represented 48 * as either an absolute URL or a relative one. 49 */ 50 reloadableScripts: [], 51 /** 52 * The selector for clickable elements that need to support confirmation and form submission. 53 */ 54 clickableSelector: 'a, button, input[type="submit"], input[type="button"], input[type="reset"], input[type="image"]', 55 /** 56 * The selector for changeable elements that need to support confirmation and form submission. 57 */ 58 changeableSelector: 'select, input, textarea', 59 60 /** 61 * @return string|undefined the CSRF parameter name. Undefined is returned if CSRF validation is not enabled. 62 */
63 getCsrfParam: function () { 64 return $('meta[name=csrf-param]').attr('content'); 65 }, 66 67 /** 68 * @return string|undefined the CSRF token. Undefined is returned if CSRF validation is not enabled. 69 */ 70 getCsrfToken: function () { 71 return $('meta[name=csrf-token]').attr('content'); 72 }, 73 74 /** 75 * Sets the CSRF token in the meta elements. 76 * This method is provided so that you can update the CSRF token with the latest one you obtain from the server. 77 * @param name the CSRF token name 78 * @param value the CSRF token value 79 */ 80 setCsrfToken: function (name, value) { 81 $('meta[name=csrf-param]').attr('content', name); 82 $('meta[name=csrf-token]').attr('content', value) 83 }, 84 85 /** 86 * Updates all form CSRF input fields with the latest CSRF token. 87 * This method is provided to avoid cached forms containing outdated CSRF tokens. 88 */ 89 refreshCsrfToken: function () { 90 var token = pub.getCsrfToken(); 91 if (token) { 92 $('form input[name="' + pub.getCsrfParam() + '"]').val(token); 93 } 94 }, 95 96 /** 97 * Displays a confirmation dialog. 98 * The default implementation simply displays a js confirmation dialog. 99 * You may override this by setting `yii.confirm`. 100 * @param message the confirmation message. 101 * @param ok a callback to be called when the user confirms the message 102 * @param cancel a callback to be called when the user cancels the confirmation 103 */ 104 confirm: function (message, ok, cancel) { 105 if (confirm(message)) { 106 !ok || ok(); 107 } else { 108 !cancel || cancel(); 109 } 110 }, 111 112 /** 113 * Handles the action triggered by user. 114 * This method recognizes the `data-method` attribute of the element. If the attribute exists, 115 * the method will submit the form containing this element. If there is no containing form, a form 116 * will be created and submitted using the method given by this attribute value (e.g. "post", "put"). 117 * For hyperlinks, the form action will take the value of the "href" attribute of the link. 118 * For other elements, either the containing form action or the current page URL will be used 119 * as the form action URL. 120 * 121 * If the `data-method` attribute is not defined, the `href` attribute (if any) of the element 122 * will be assigned to `window.location`. 123 * 124 * Starting from version 2.0.3, the `data-params` attribute is also recognized when you specify 125 * `data-method`. The value of `data-params` should be a JSON representation of the data (name-value pairs) 126 * that should be submitted as hidden inputs. For example, you may use the following code to generate 127 * such a link: 128 * 129 * ```php 130 * use yii\helpers\Html; 131 * use yii\helpers\Json; 132 * 133 * echo Html::a('submit', ['site/foobar'], [ 134 * 'data' => [ 135 * 'method' => 'post', 136 * 'params' => [ 137 * 'name1' => 'value1', 138 * 'name2' => 'value2', 139 * ], 140 * ], 141 * ]; 142 * ``` 143 * 144 * @param $e the jQuery representation of the element 145 */ 146 handleAction: function ($e) { 147 var method = $e.data('method'), 148 $form = $e.closest('form'), 149 action = $e.attr('href'), 150 params = $e.data('params'); 151 152 if (method === undefined) { 153 if (action && action != '#') { 154 window.location = action; 155 } else if ($e.is(':submit') && $form.length) { 156 $form.trigger('submit'); 157 } 158 return; 159 } 160 161 var newForm = !$form.length; 162 if (newForm) { 163 if (!action || !action.match(/(^\/|:\/\/)/)) { 164 action = window.location.href; 165 } 166 $form = $('<form method="' + method + '"></form>'); 167 $form.attr('action', action); 168 var target = $e.attr('target'); 169 if (target) { 170 $form.attr('target', target); 171 } 172 if (!method.match(/(get|post)/i)) { 173 $form.append('<input name="_method" value="' + method + '" type="hidden">'); 174 method = 'POST'; 175 } 176 if (!method.match(/(get|head|options)/i)) { 177 var csrfParam = pub.getCsrfParam(); 178 if (csrfParam) { 179 $form.append('<input name="' + csrfParam + '" value="' + pub.getCsrfToken() + '" type="hidden">'); 180 } 181 } 182 $form.hide().appendTo('body'); 183 } 184 185 var activeFormData = $form.data('yiiActiveForm'); 186 if (activeFormData) { 187 // remember who triggers the form submission. This is used by yii.activeForm.js 188 activeFormData.submitObject = $e; 189 } 190
191 // temporarily add hidden inputs according to data-params 192 if (params && $.isPlainObject(params)) { 193 $.each(params, function (idx, obj) { 194 $form.append('<input name="' + idx + '" value="' + obj + '" type="hidden">'); 195 }); 196 } 197 198 var oldMethod = $form.attr('method'); 199 $form.attr('method', method); 200 var oldAction = null; 201 if (action && action != '#') { 202 oldAction = $form.attr('action'); 203 $form.attr('action', action); 204 } 205 206 $form.trigger('submit'); 207 208 if (oldAction != null) { 209 $form.attr('action', oldAction); 210 } 211 $form.attr('method', oldMethod); 212 213 // remove the temporarily added hidden inputs 214 if (params && $.isPlainObject(params)) { 215 $.each(params, function (idx, obj) { 216 $('input[name="' + idx + '"]', $form).remove(); 217 }); 218 } 219 220 if (newForm) { 221 $form.remove(); 222 } 223 }, 224 225 getQueryParams: function (url) { 226 var pos = url.indexOf('?'); 227 if (pos < 0) { 228 return {}; 229 } 230 var qs = url.substring(pos + 1).split('&'); 231 for (var i = 0, result = {}; i < qs.length; i++) { 232 qs[i] = qs[i].split('='); 233 result[decodeURIComponent(qs[i][0])] = decodeURIComponent(qs[i][1]); 234 } 235 return result; 236 }, 237 238 initModule: function (module) { 239 if (module.isActive === undefined || module.isActive) { 240 if ($.isFunction(module.init)) { 241 module.init(); 242 } 243 $.each(module, function () { 244 if ($.isPlainObject(this)) { 245 pub.initModule(this); 246 } 247 }); 248 } 249 }, 250 251 init: function () { 252 initCsrfHandler(); 253 initRedirectHandler(); 254 initScriptFilter(); 255 initDataMethods(); 256 } 257 }; 258 259 function initRedirectHandler() { 260 // handle AJAX redirection 261 $(document).ajaxComplete(function (event, xhr, settings) { 262 var url = xhr.getResponseHeader('X-Redirect'); 263 if (url) { 264 window.location = url; 265 } 266 }); 267 } 268 269 function initCsrfHandler() { 270 // automatically send CSRF token for all AJAX requests 271 $.ajaxPrefilter(function (options, originalOptions, xhr) { 272 if (!options.crossDomain && pub.getCsrfParam()) { 273 xhr.setRequestHeader('X-CSRF-Token', pub.getCsrfToken()); 274 } 275 }); 276 pub.refreshCsrfToken(); 277 } 278 279 function initDataMethods() { 280 var handler = function (event) { 281 var $this = $(this), 282 method = $this.data('method'), 283 message = $this.data('confirm'); 284 285 if (method === undefined && message === undefined) { 286 return true; 287 } 288 289 if (message !== undefined) { 290 pub.confirm(message, function () { 291 pub.handleAction($this); 292 }); 293 } else { 294 pub.handleAction($this); 295 } 296 event.stopImmediatePropagation(); 297 return false; 298 }; 299 300 // handle data-confirm and data-method for clickable and changeable elements 301 $(document).on('click.yii', pub.clickableSelector, handler) 302 .on('change.yii', pub.changeableSelector, handler); 303 } 304 305 function initScriptFilter() { 306 var hostInfo = location.protocol + '//' + location.host; 307 var loadedScripts = $('script[src]').map(function () { 308 return this.src.charAt(0) === '/' ? hostInfo + this.src : this.src; 309 }).toArray(); 310 311 $.ajaxPrefilter('script', function (options, originalOptions, xhr) { 312 if (options.dataType == 'jsonp') { 313 return; 314 } 315 var url = options.url.charAt(0) === '/' ? hostInfo + options.url : options.url; 316 if ($.inArray(url, loadedScripts) === -1) { 317 loadedScripts.push(url); 318 } else { 319 var found = $.inArray(url, $.map(pub.reloadableScripts, function (script) { 320 return script.charAt(0) === '/' ? hostInfo + script : script; 321 })) !== -1; 322 if (!found) { 323 xhr.abort(); 324 } 325 } 326 }); 327 328 $(document).ajaxComplete(function (event, xhr, settings) { 329 var styleSheets = []; 330 $('link[rel=stylesheet]').each(function () { 331 if ($.inArray(this.href, pub.reloadableScripts) !== -1) { 332 return; 333 } 334 if ($.inArray(this.href, styleSheets) == -1) { 335 styleSheets.push(this.href) 336 } else { 337 $(this).remove(); 338 } 339 }) 340 }); 341 } 342 343 return pub; 344})(jQuery); 345 346jQuery(document).ready(function () { 347 yii.initModule(yii); 348});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.