mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-11-04 06:37:55 +08:00 
			
		
		
		
	Merge branch 'bugfix/20002-Superfluous_query_on_HEAD_request_in_serializer' of https://github.com/xicond/yii2 into bugfix/20002-Superfluous_query_on_HEAD_request_in_serializer
This commit is contained in:
		@ -76,8 +76,8 @@
 | 
				
			|||||||
        "ezyang/htmlpurifier": "^4.6",
 | 
					        "ezyang/htmlpurifier": "^4.6",
 | 
				
			||||||
        "cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0",
 | 
					        "cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0",
 | 
				
			||||||
        "bower-asset/jquery": "3.7.*@stable | 3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
 | 
					        "bower-asset/jquery": "3.7.*@stable | 3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
 | 
				
			||||||
        "bower-asset/inputmask": "~3.2.2 | ~3.3.5 | ~5.0.8 ",
 | 
					        "bower-asset/inputmask": "^5.0.8 ",
 | 
				
			||||||
        "bower-asset/punycode": "1.3.* | 2.2.*",
 | 
					        "bower-asset/punycode": "^2.2",
 | 
				
			||||||
        "bower-asset/yii2-pjax": "~2.0.1",
 | 
					        "bower-asset/yii2-pjax": "~2.0.1",
 | 
				
			||||||
        "paragonie/random_compat": ">=1"
 | 
					        "paragonie/random_compat": ">=1"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,8 @@ Yii Framework 2 Change Log
 | 
				
			|||||||
2.0.50 under development
 | 
					2.0.50 under development
 | 
				
			||||||
------------------------
 | 
					------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Bug #13920: Fixed erroneous validation for specific cases (tim-fischer-maschinensucher)
 | 
				
			||||||
 | 
					- Bug #19927: Fixed `console\controllers\MessageController` when saving translations to database: fixed FK error when adding new string and language at the same time, checking/regenerating all missing messages and dropping messages for unused languages (atrandafir)
 | 
				
			||||||
- Enh #12743: Added new methods `BaseActiveRecord::loadRelations()` and `BaseActiveRecord::loadRelationsFor()` to eager load related models for existing primary model instances (PowerGamer1)
 | 
					- Enh #12743: Added new methods `BaseActiveRecord::loadRelations()` and `BaseActiveRecord::loadRelationsFor()` to eager load related models for existing primary model instances (PowerGamer1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -395,9 +395,11 @@
 | 
				
			|||||||
                        data: $form.serialize() + extData,
 | 
					                        data: $form.serialize() + extData,
 | 
				
			||||||
                        dataType: data.settings.ajaxDataType,
 | 
					                        dataType: data.settings.ajaxDataType,
 | 
				
			||||||
                        complete: function (jqXHR, textStatus) {
 | 
					                        complete: function (jqXHR, textStatus) {
 | 
				
			||||||
 | 
					                            currentAjaxRequest = null;
 | 
				
			||||||
                            $form.trigger(events.ajaxComplete, [jqXHR, textStatus]);
 | 
					                            $form.trigger(events.ajaxComplete, [jqXHR, textStatus]);
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                        beforeSend: function (jqXHR, settings) {
 | 
					                        beforeSend: function (jqXHR, settings) {
 | 
				
			||||||
 | 
					                            currentAjaxRequest = jqXHR;
 | 
				
			||||||
                            $form.trigger(events.ajaxBeforeSend, [jqXHR, settings]);
 | 
					                            $form.trigger(events.ajaxBeforeSend, [jqXHR, settings]);
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                        success: function (msgs) {
 | 
					                        success: function (msgs) {
 | 
				
			||||||
@ -563,6 +565,9 @@
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (currentAjaxRequest !== null) {
 | 
				
			||||||
 | 
					            currentAjaxRequest.abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        if (data.settings.timer !== undefined) {
 | 
					        if (data.settings.timer !== undefined) {
 | 
				
			||||||
            clearTimeout(data.settings.timer);
 | 
					            clearTimeout(data.settings.timer);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -929,4 +934,7 @@
 | 
				
			|||||||
            $form.find(attribute.input).attr('aria-invalid', hasError ? 'true' : 'false');
 | 
					            $form.find(attribute.input).attr('aria-invalid', hasError ? 'true' : 'false');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var currentAjaxRequest = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
})(window.jQuery);
 | 
					})(window.jQuery);
 | 
				
			||||||
 | 
				
			|||||||
@ -71,8 +71,8 @@
 | 
				
			|||||||
        "ezyang/htmlpurifier": "^4.6",
 | 
					        "ezyang/htmlpurifier": "^4.6",
 | 
				
			||||||
        "cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0",
 | 
					        "cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0",
 | 
				
			||||||
        "bower-asset/jquery": "3.7.*@stable | 3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
 | 
					        "bower-asset/jquery": "3.7.*@stable | 3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
 | 
				
			||||||
        "bower-asset/inputmask": "~3.2.2 | ~3.3.5 | ~5.0.8 ",
 | 
					        "bower-asset/inputmask": "^5.0.8 ",
 | 
				
			||||||
        "bower-asset/punycode": "1.3.* | 2.2.*",
 | 
					        "bower-asset/punycode": "^2.2",
 | 
				
			||||||
        "bower-asset/yii2-pjax": "~2.0.1",
 | 
					        "bower-asset/yii2-pjax": "~2.0.1",
 | 
				
			||||||
        "paragonie/random_compat": ">=1"
 | 
					        "paragonie/random_compat": ">=1"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
				
			|||||||
@ -354,16 +354,6 @@ EOD;
 | 
				
			|||||||
            $currentMessages[$row['category']][$row['id']] = $row['message'];
 | 
					            $currentMessages[$row['category']][$row['id']] = $row['message'];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        $currentLanguages = [];
 | 
					 | 
				
			||||||
        $rows = (new Query())->select(['language'])->from($messageTable)->groupBy('language')->all($db);
 | 
					 | 
				
			||||||
        foreach ($rows as $row) {
 | 
					 | 
				
			||||||
            $currentLanguages[] = $row['language'];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        $missingLanguages = [];
 | 
					 | 
				
			||||||
        if (!empty($currentLanguages)) {
 | 
					 | 
				
			||||||
            $missingLanguages = array_diff($languages, $currentLanguages);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $new = [];
 | 
					        $new = [];
 | 
				
			||||||
        $obsolete = [];
 | 
					        $obsolete = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -372,91 +362,132 @@ EOD;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (isset($currentMessages[$category])) {
 | 
					            if (isset($currentMessages[$category])) {
 | 
				
			||||||
                $new[$category] = array_diff($msgs, $currentMessages[$category]);
 | 
					                $new[$category] = array_diff($msgs, $currentMessages[$category]);
 | 
				
			||||||
 | 
					                // obsolete messages per category
 | 
				
			||||||
                $obsolete += array_diff($currentMessages[$category], $msgs);
 | 
					                $obsolete += array_diff($currentMessages[$category], $msgs);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                $new[$category] = $msgs;
 | 
					                $new[$category] = $msgs;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        // obsolete categories
 | 
				
			||||||
        foreach (array_diff(array_keys($currentMessages), array_keys($messages)) as $category) {
 | 
					        foreach (array_diff(array_keys($currentMessages), array_keys($messages)) as $category) {
 | 
				
			||||||
            $obsolete += $currentMessages[$category];
 | 
					            $obsolete += $currentMessages[$category];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!$removeUnused) {
 | 
					        if (!$removeUnused) {
 | 
				
			||||||
            foreach ($obsolete as $pk => $msg) {
 | 
					            foreach ($obsolete as $pk => $msg) {
 | 
				
			||||||
 | 
					                // skip already marked unused
 | 
				
			||||||
                if (strncmp($msg, '@@', 2) === 0 && substr($msg, -2) === '@@') {
 | 
					                if (strncmp($msg, '@@', 2) === 0 && substr($msg, -2) === '@@') {
 | 
				
			||||||
                    unset($obsolete[$pk]);
 | 
					                    unset($obsolete[$pk]);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }        
 | 
					        }        
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        $obsolete = array_keys($obsolete);
 | 
					 | 
				
			||||||
        $this->stdout('Inserting new messages...');
 | 
					        $this->stdout('Inserting new messages...');
 | 
				
			||||||
        $savedFlag = false;
 | 
					        $insertCount = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        foreach ($new as $category => $msgs) {
 | 
					        foreach ($new as $category => $msgs) {
 | 
				
			||||||
            foreach ($msgs as $msg) {
 | 
					            foreach ($msgs as $msg) {
 | 
				
			||||||
                $savedFlag = true;
 | 
					                $insertCount++;
 | 
				
			||||||
                $lastPk = $db->schema->insert($sourceMessageTable, ['category' => $category, 'message' => $msg]);
 | 
					                $db->schema->insert($sourceMessageTable, ['category' => $category, 'message' => $msg]);
 | 
				
			||||||
                foreach ($languages as $language) {
 | 
					 | 
				
			||||||
                    $db->createCommand()
 | 
					 | 
				
			||||||
                       ->insert($messageTable, ['id' => $lastPk['id'], 'language' => $language])
 | 
					 | 
				
			||||||
                       ->execute();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!empty($missingLanguages)) {
 | 
					 | 
				
			||||||
            $updatedMessages = [];
 | 
					 | 
				
			||||||
            $rows = (new Query())->select(['id', 'category', 'message'])->from($sourceMessageTable)->all($db);
 | 
					 | 
				
			||||||
            foreach ($rows as $row) {
 | 
					 | 
				
			||||||
                $updatedMessages[$row['category']][$row['id']] = $row['message'];
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            foreach ($updatedMessages as $category => $msgs) {
 | 
					 | 
				
			||||||
                foreach ($msgs as $id => $msg) {
 | 
					 | 
				
			||||||
                    $savedFlag = true;
 | 
					 | 
				
			||||||
                    foreach ($missingLanguages as $language) {
 | 
					 | 
				
			||||||
                        $db->createCommand()
 | 
					 | 
				
			||||||
                            ->insert($messageTable, ['id' => $id, 'language' => $language])
 | 
					 | 
				
			||||||
                            ->execute();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        $this->stdout($savedFlag ? "saved.\n" : "Nothing to save.\n");
 | 
					        $this->stdout($insertCount ? "{$insertCount} saved.\n" : "Nothing to save.\n");
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        $this->stdout($removeUnused ? 'Deleting obsoleted messages...' : 'Updating obsoleted messages...');
 | 
					        $this->stdout($removeUnused ? 'Deleting obsoleted messages...' : 'Updating obsoleted messages...');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (empty($obsolete)) {
 | 
					        if (empty($obsolete)) {
 | 
				
			||||||
            $this->stdout("Nothing obsoleted...skipped.\n");
 | 
					            $this->stdout("Nothing obsoleted...skipped.\n");
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($obsolete) {
 | 
				
			||||||
            if ($removeUnused) {
 | 
					            if ($removeUnused) {
 | 
				
			||||||
            $db->createCommand()
 | 
					                $affected = $db->createCommand()
 | 
				
			||||||
               ->delete($sourceMessageTable, ['in', 'id', $obsolete])
 | 
					                   ->delete($sourceMessageTable, ['in', 'id', array_keys($obsolete)])
 | 
				
			||||||
                   ->execute();
 | 
					                   ->execute();
 | 
				
			||||||
            $this->stdout("deleted.\n");
 | 
					                $this->stdout("{$affected} deleted.\n");
 | 
				
			||||||
            } elseif ($markUnused) {
 | 
					            } elseif ($markUnused) {
 | 
				
			||||||
 | 
					                $marked=0;
 | 
				
			||||||
                $rows = (new Query())
 | 
					                $rows = (new Query())
 | 
				
			||||||
                    ->select(['id', 'message'])
 | 
					                    ->select(['id', 'message'])
 | 
				
			||||||
                    ->from($sourceMessageTable)
 | 
					                    ->from($sourceMessageTable)
 | 
				
			||||||
                ->where(['in', 'id', $obsolete])
 | 
					                    ->where(['in', 'id', array_keys($obsolete)])
 | 
				
			||||||
                    ->all($db);
 | 
					                    ->all($db);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
                foreach ($rows as $row) {
 | 
					                foreach ($rows as $row) {
 | 
				
			||||||
 | 
					                    $marked++;
 | 
				
			||||||
                    $db->createCommand()->update(
 | 
					                    $db->createCommand()->update(
 | 
				
			||||||
                        $sourceMessageTable,
 | 
					                        $sourceMessageTable,
 | 
				
			||||||
                        ['message' => '@@' . $row['message'] . '@@'],
 | 
					                        ['message' => '@@' . $row['message'] . '@@'],
 | 
				
			||||||
                        ['id' => $row['id']]
 | 
					                        ['id' => $row['id']]
 | 
				
			||||||
                    )->execute();
 | 
					                    )->execute();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            $this->stdout("updated.\n");
 | 
					                $this->stdout("{$marked} updated.\n");
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                $this->stdout("kept untouched.\n");
 | 
					                $this->stdout("kept untouched.\n");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        // get fresh message id list
 | 
				
			||||||
 | 
					        $freshMessagesIds = [];
 | 
				
			||||||
 | 
					        $rows = (new Query())->select(['id'])->from($sourceMessageTable)->all($db);
 | 
				
			||||||
 | 
					        foreach ($rows as $row) {
 | 
				
			||||||
 | 
					            $freshMessagesIds[] = $row['id'];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        $this->stdout("Generating missing rows...");
 | 
				
			||||||
 | 
					        $generatedMissingRows = [];
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        foreach ($languages as $language) {
 | 
				
			||||||
 | 
					          $count = 0;
 | 
				
			||||||
 | 
					          
 | 
				
			||||||
 | 
					          // get list of ids of translations for this language
 | 
				
			||||||
 | 
					          $msgRowsIds = [];
 | 
				
			||||||
 | 
					          $msgRows = (new Query())->select(['id'])->from($messageTable)->where([
 | 
				
			||||||
 | 
					              'language'=>$language,
 | 
				
			||||||
 | 
					          ])->all($db);
 | 
				
			||||||
 | 
					          foreach ($msgRows as $row) {
 | 
				
			||||||
 | 
					              $msgRowsIds[] = $row['id'];
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          
 | 
				
			||||||
 | 
					          // insert missing
 | 
				
			||||||
 | 
					          foreach ($freshMessagesIds as $id) {
 | 
				
			||||||
 | 
					            if (!in_array($id, $msgRowsIds)) {
 | 
				
			||||||
 | 
					              $db->createCommand()
 | 
				
			||||||
 | 
					                 ->insert($messageTable, ['id' => $id, 'language' => $language])
 | 
				
			||||||
 | 
					                 ->execute();
 | 
				
			||||||
 | 
					              $count++;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if ($count) {
 | 
				
			||||||
 | 
					            $generatedMissingRows[] = "{$count} for {$language}";
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $this->stdout($generatedMissingRows ? implode(", ", $generatedMissingRows).".\n" : "Nothing to do.\n");
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $this->stdout("Dropping unused languages...");
 | 
				
			||||||
 | 
					        $droppedLanguages=[];
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $currentLanguages = [];
 | 
				
			||||||
 | 
					        $rows = (new Query())->select(['language'])->from($messageTable)->groupBy('language')->all($db);
 | 
				
			||||||
 | 
					        foreach ($rows as $row) {
 | 
				
			||||||
 | 
					            $currentLanguages[] = $row['language'];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        foreach ($currentLanguages as $currentLanguage) {
 | 
				
			||||||
 | 
					          if (!in_array($currentLanguage, $languages)) {
 | 
				
			||||||
 | 
					            $deleted=$db->createCommand()->delete($messageTable, "language=:language", [
 | 
				
			||||||
 | 
					                'language'=>$currentLanguage,
 | 
				
			||||||
 | 
					            ])->execute();
 | 
				
			||||||
 | 
					            $droppedLanguages[] = "removed {$deleted} rows for $currentLanguage";
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $this->stdout($droppedLanguages ? implode(", ", $droppedLanguages).".\n" : "Nothing to do.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Extracts messages from a file.
 | 
					     * Extracts messages from a file.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
@ -80,7 +80,7 @@ class ServeController extends Controller
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        $this->stdout("Quit the server with CTRL-C or COMMAND-C.\n");
 | 
					        $this->stdout("Quit the server with CTRL-C or COMMAND-C.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        passthru('"' . PHP_BINARY . '"' . " -S {$address} -t \"{$documentRoot}\" $router");
 | 
					        passthru('"' . PHP_BINARY . '"' . " -S {$address} -t \"{$documentRoot}\" \"$router\"");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,7 @@ class MaskedInputAsset extends AssetBundle
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public $sourcePath = '@bower/inputmask/dist';
 | 
					    public $sourcePath = '@bower/inputmask/dist';
 | 
				
			||||||
    public $js = [
 | 
					    public $js = [
 | 
				
			||||||
        'jquery.inputmask.bundle.js',
 | 
					        'jquery.inputmask.js',
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
    public $depends = [
 | 
					    public $depends = [
 | 
				
			||||||
        'yii\web\YiiAsset',
 | 
					        'yii\web\YiiAsset',
 | 
				
			||||||
 | 
				
			|||||||
@ -48,3 +48,15 @@
 | 
				
			|||||||
        <div class="help-block"></div>
 | 
					        <div class="help-block"></div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</form>
 | 
					</form>
 | 
				
			||||||
 | 
					<form id="w3">
 | 
				
			||||||
 | 
					    <div class="form-group field-test-text2 required">
 | 
				
			||||||
 | 
					        <label class="control-label" for="test-text2">Test text</label>
 | 
				
			||||||
 | 
					        <input type="text" id="test-text2" class="form-control" name="Test[text2]" aria-required="true">
 | 
				
			||||||
 | 
					        <div class="help-block"></div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div class="form-group field-test-text3 required">
 | 
				
			||||||
 | 
					        <label class="control-label" for="test-text3">Test text</label>
 | 
				
			||||||
 | 
					        <input type="text" id="test-text3" class="form-control" name="Test[text3]" aria-required="true">
 | 
				
			||||||
 | 
					        <div class="help-block"></div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
 | 
				
			|||||||
@ -27,6 +27,21 @@ describe('yii.activeForm', function () {
 | 
				
			|||||||
        var script = new vm.Script(code);
 | 
					        var script = new vm.Script(code);
 | 
				
			||||||
        var context = new vm.createContext({window: window, document: window.document, yii: yii});
 | 
					        var context = new vm.createContext({window: window, document: window.document, yii: yii});
 | 
				
			||||||
        script.runInContext(context);
 | 
					        script.runInContext(context);
 | 
				
			||||||
 | 
					        /** This is a workaround for a jsdom issue, that prevents :hidden and :visible from working as expected.
 | 
				
			||||||
 | 
					         * @see https://github.com/jsdom/jsdom/issues/1048 */
 | 
				
			||||||
 | 
					        context.window.Element.prototype.getClientRects = function () {
 | 
				
			||||||
 | 
					            var node = this;
 | 
				
			||||||
 | 
					            while(node) {
 | 
				
			||||||
 | 
					                if(node === document) {
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (!node.style || node.style.display === 'none' || node.style.visibility === 'hidden') {
 | 
				
			||||||
 | 
					                    return [];
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                node = node.parentNode;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return [{width: 100, height: 100}];
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var activeFormHtml = fs.readFileSync('tests/js/data/yii.activeForm.html', 'utf-8');
 | 
					    var activeFormHtml = fs.readFileSync('tests/js/data/yii.activeForm.html', 'utf-8');
 | 
				
			||||||
@ -117,6 +132,60 @@ describe('yii.activeForm', function () {
 | 
				
			|||||||
                assert.isFalse($activeForm.data('yiiActiveForm').validated);
 | 
					                assert.isFalse($activeForm.data('yiiActiveForm').validated);
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        describe('with ajax validation', function () {
 | 
				
			||||||
 | 
					            describe('with rapid validation of multiple fields', function () {
 | 
				
			||||||
 | 
					                it('should cancel overlapping ajax requests and not display outdated validation results', function () {
 | 
				
			||||||
 | 
					                    $activeForm = $('#w3');
 | 
				
			||||||
 | 
					                    $activeForm.yiiActiveForm([{
 | 
				
			||||||
 | 
					                        id: 'test-text2',
 | 
				
			||||||
 | 
					                        input: '#test-text2',
 | 
				
			||||||
 | 
					                        container: '.field-test-text2',
 | 
				
			||||||
 | 
					                        enableAjaxValidation: true
 | 
				
			||||||
 | 
					                    }, {
 | 
				
			||||||
 | 
					                        id: 'test-text3',
 | 
				
			||||||
 | 
					                        input: '#test-text3',
 | 
				
			||||||
 | 
					                        container: '.field-test-text3',
 | 
				
			||||||
 | 
					                        enableAjaxValidation: true
 | 
				
			||||||
 | 
					                    }], {
 | 
				
			||||||
 | 
					                        validationUrl: ''
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let requests = [];
 | 
				
			||||||
 | 
					                    function fakeAjax(object) {
 | 
				
			||||||
 | 
					                        const request = {
 | 
				
			||||||
 | 
					                            jqXHR: {
 | 
				
			||||||
 | 
					                                abort: function () {
 | 
				
			||||||
 | 
					                                    request.aborted = true;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            aborted: false,
 | 
				
			||||||
 | 
					                            respond: function (response) {
 | 
				
			||||||
 | 
					                                if (this.aborted) {
 | 
				
			||||||
 | 
					                                    return;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                object.success(response);
 | 
				
			||||||
 | 
					                                object.complete(this.jqXHR, '');
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        };
 | 
				
			||||||
 | 
					                        requests.push(request);
 | 
				
			||||||
 | 
					                        object.beforeSend(request.jqXHR, '');
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    const ajaxStub = sinon.stub($, 'ajax', fakeAjax);
 | 
				
			||||||
 | 
					                    $activeForm.yiiActiveForm('validateAttribute', 'test-text2');
 | 
				
			||||||
 | 
					                    assert.isTrue(requests.length === 1);
 | 
				
			||||||
 | 
					                    $activeForm.yiiActiveForm('validateAttribute', 'test-text3');
 | 
				
			||||||
 | 
					                    // When validateAttribute was called on text2, its value was valid.
 | 
				
			||||||
 | 
					                    // The value of text3 wasn't.
 | 
				
			||||||
 | 
					                    requests[0].respond({'test-text3': ['Field cannot be empty']});
 | 
				
			||||||
 | 
					                    // When validateAttribute was called on text3, its value was valid.
 | 
				
			||||||
 | 
					                    requests[1].respond([]);
 | 
				
			||||||
 | 
					                    assert.isTrue($activeForm.find('.field-test-text3').hasClass('has-success'));
 | 
				
			||||||
 | 
					                    ajaxStub.restore();
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe('resetForm method', function () {
 | 
					    describe('resetForm method', function () {
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user