diff --git a/glances/outputs/static/js/components/plugin-sensors/controller.js b/glances/outputs/static/js/components/plugin-sensors/controller.js index 121a42da..a7e0924a 100644 --- a/glances/outputs/static/js/components/plugin-sensors/controller.js +++ b/glances/outputs/static/js/components/plugin-sensors/controller.js @@ -1,8 +1,9 @@ 'use strict'; -function GlancesPluginSensorsController($scope, GlancesStats, GlancesPluginHelper) { +function GlancesPluginSensorsController($scope, GlancesStats, GlancesPluginHelper, ARGUMENTS) { var vm = this; vm.sensors = []; + var convertToFahrenheit = ARGUMENTS.fahrenheit; vm.$onInit = function () { loadData(GlancesStats.getData()); @@ -19,6 +20,13 @@ function GlancesPluginSensorsController($scope, GlancesStats, GlancesPluginHelpe return (_.isArray(sensor.value) && _.isEmpty(sensor.value)) || sensor.value === 0; }); + _.forEach(stats, function (sensor) { + if (convertToFahrenheit && sensor.type != 'battery' && sensor.type != 'fan_speed') { + sensor.value = parseFloat(sensor.value * 1.8 + 32).toFixed(1); + sensor.unit = 'F'; + } + }); + vm.sensors = stats; }; diff --git a/glances/outputs/static/public/js/main.min.js b/glances/outputs/static/public/js/main.min.js index 9e46b397..a410a9da 100644 --- a/glances/outputs/static/public/js/main.min.js +++ b/glances/outputs/static/public/js/main.min.js @@ -853,7 +853,7 @@ function GlancesPluginDockerController($scope, GlancesStats) { vm.containers = stats['containers'].map(function(containerData) { return { 'id': containerData.Id, - 'name': containerData.Names[0].split('/').splice(-1)[0], + 'name': containerData.name, 'status': containerData.Status, 'cpu': containerData.cpu.total, 'memory': containerData.memory.usage != undefined ? containerData.memory.usage : '?', @@ -874,65 +874,6 @@ function GlancesPluginDockerController($scope, GlancesStats) { 'use strict'; -glancesApp.component('glancesPluginFolders', { - controller: GlancesPluginFsController, - controllerAs: 'vm', - templateUrl: 'components/plugin-folders/view.html' -}); - -'use strict'; - -function GlancesPluginFoldersController($scope, GlancesStats) { - var vm = this; - vm.folders = []; - - vm.$onInit = function () { - loadData(GlancesStats.getData()); - }; - - $scope.$on('data_refreshed', function (event, data) { - loadData(data); - }); - - var loadData = function (data) { - var stats = data.stats['folders']; - vm.folders = []; - - for (var i = 0; i < stats.length; i++) { - var folderData = stats[i]; - - var folder = { - 'path': folderData['path'], - 'size': folderData['size'], - 'careful': folderData['careful'], - 'warning': folderData['warning'], - 'critical': folderData['critical'] - }; - - vm.folders.push(folder); - } - } - - vm.getDecoration = function (folder) { - - if (!Number.isInteger(folder.size)) { - return; - } - - if (folder.critical !== null && folder.size > (folder.critical * 1000000)) { - return 'critical'; - } else if (folder.warning !== null && folder.size > (folder.warning * 1000000)) { - return 'warning'; - } else if (folder.careful !== null && folder.size > (folder.careful * 1000000)) { - return 'careful'; - } - - return 'ok'; - }; -} - -'use strict'; - glancesApp.component('glancesPluginFs', { controller: GlancesPluginFsController, controllerAs: 'vm', @@ -1069,6 +1010,65 @@ function GlancesPluginGpuController($scope, GlancesStats, ARGUMENTS) { 'use strict'; +glancesApp.component('glancesPluginFolders', { + controller: GlancesPluginFsController, + controllerAs: 'vm', + templateUrl: 'components/plugin-folders/view.html' +}); + +'use strict'; + +function GlancesPluginFoldersController($scope, GlancesStats) { + var vm = this; + vm.folders = []; + + vm.$onInit = function () { + loadData(GlancesStats.getData()); + }; + + $scope.$on('data_refreshed', function (event, data) { + loadData(data); + }); + + var loadData = function (data) { + var stats = data.stats['folders']; + vm.folders = []; + + for (var i = 0; i < stats.length; i++) { + var folderData = stats[i]; + + var folder = { + 'path': folderData['path'], + 'size': folderData['size'], + 'careful': folderData['careful'], + 'warning': folderData['warning'], + 'critical': folderData['critical'] + }; + + vm.folders.push(folder); + } + } + + vm.getDecoration = function (folder) { + + if (!Number.isInteger(folder.size)) { + return; + } + + if (folder.critical !== null && folder.size > (folder.critical * 1000000)) { + return 'critical'; + } else if (folder.warning !== null && folder.size > (folder.warning * 1000000)) { + return 'warning'; + } else if (folder.careful !== null && folder.size > (folder.careful * 1000000)) { + return 'careful'; + } + + return 'ok'; + }; +} + +'use strict'; + glancesApp.component('glancesPluginIp', { controller: GlancesPluginIpController, controllerAs: 'vm', @@ -1147,52 +1147,6 @@ function GlancesPluginIrqController($scope, GlancesStats) { 'use strict'; -glancesApp.component('glancesPluginLoad', { - controller: GlancesPluginLoadController, - controllerAs: 'vm', - templateUrl: 'components/plugin-load/view.html' -}); - -'use strict'; - -function GlancesPluginLoadController($scope, GlancesStats) { - var vm = this; - var _view = {}; - - vm.cpucore = null; - vm.min1 = null; - vm.min5 = null; - vm.min15 = null; - - vm.$onInit = function () { - loadData(GlancesStats.getData()); - }; - - $scope.$on('data_refreshed', function (event, data) { - loadData(data); - }); - - var loadData = function (data) { - var stats = data.stats['load']; - _view = data.views['load']; - - vm.cpucore = stats['cpucore']; - vm.min1 = stats['min1']; - vm.min5 = stats['min5']; - vm.min15 = stats['min15']; - }; - - vm.getDecoration = function (value) { - if (_view[value] === undefined) { - return; - } - - return _view[value].decoration.toLowerCase(); - }; -} - -'use strict'; - glancesApp.component('glancesPluginMem', { controller: GlancesPluginMemController, controllerAs: 'vm', @@ -1275,6 +1229,52 @@ function GlancesPluginMemMoreController($scope, GlancesStats) { 'use strict'; +glancesApp.component('glancesPluginLoad', { + controller: GlancesPluginLoadController, + controllerAs: 'vm', + templateUrl: 'components/plugin-load/view.html' +}); + +'use strict'; + +function GlancesPluginLoadController($scope, GlancesStats) { + var vm = this; + var _view = {}; + + vm.cpucore = null; + vm.min1 = null; + vm.min5 = null; + vm.min15 = null; + + vm.$onInit = function () { + loadData(GlancesStats.getData()); + }; + + $scope.$on('data_refreshed', function (event, data) { + loadData(data); + }); + + var loadData = function (data) { + var stats = data.stats['load']; + _view = data.views['load']; + + vm.cpucore = stats['cpucore']; + vm.min1 = stats['min1']; + vm.min5 = stats['min5']; + vm.min15 = stats['min15']; + }; + + vm.getDecoration = function (value) { + if (_view[value] === undefined) { + return; + } + + return _view[value].decoration.toLowerCase(); + }; +} + +'use strict'; + glancesApp.component('glancesPluginMemswap', { controller: GlancesPluginMemswapController, controllerAs: 'vm', @@ -1321,6 +1321,54 @@ function GlancesPluginMemswapController($scope, GlancesStats) { 'use strict'; +glancesApp.component('glancesPluginNetwork', { + controller: GlancesPluginNetworkController, + controllerAs: 'vm', + templateUrl: 'components/plugin-network/view.html' +}); + +'use strict'; + +function GlancesPluginNetworkController($scope, $filter, GlancesStats, ARGUMENTS) { + var vm = this; + vm.arguments = ARGUMENTS; + vm.networks = []; + + vm.$onInit = function () { + loadData(GlancesStats.getData()); + }; + + $scope.$on('data_refreshed', function (event, data) { + loadData(data); + }); + + var loadData = function (data) { + var networkStats = data.stats['network']; + + vm.networks = []; + for (var i = 0; i < networkStats.length; i++) { + var networkData = networkStats[i]; + + var network = { + 'interfaceName': networkData['interface_name'], + 'rx': networkData['rx'], + 'tx': networkData['tx'], + 'cx': networkData['cx'], + 'time_since_update': networkData['time_since_update'], + 'cumulativeRx': networkData['cumulative_rx'], + 'cumulativeTx': networkData['cumulative_tx'], + 'cumulativeCx': networkData['cumulative_cx'] + }; + + vm.networks.push(network); + } + + vm.networks = $filter('orderBy')(vm.networks, 'interfaceName'); + } +} + +'use strict'; + glancesApp.component('glancesPluginPercpu', { controller: GlancesPluginPercpuController, controllerAs: 'vm', @@ -1372,54 +1420,6 @@ function GlancesPluginPercpuController($scope, GlancesStats, GlancesPluginHelper 'use strict'; -glancesApp.component('glancesPluginNetwork', { - controller: GlancesPluginNetworkController, - controllerAs: 'vm', - templateUrl: 'components/plugin-network/view.html' -}); - -'use strict'; - -function GlancesPluginNetworkController($scope, $filter, GlancesStats, ARGUMENTS) { - var vm = this; - vm.arguments = ARGUMENTS; - vm.networks = []; - - vm.$onInit = function () { - loadData(GlancesStats.getData()); - }; - - $scope.$on('data_refreshed', function (event, data) { - loadData(data); - }); - - var loadData = function (data) { - var networkStats = data.stats['network']; - - vm.networks = []; - for (var i = 0; i < networkStats.length; i++) { - var networkData = networkStats[i]; - - var network = { - 'interfaceName': networkData['interface_name'], - 'rx': networkData['rx'], - 'tx': networkData['tx'], - 'cx': networkData['cx'], - 'time_since_update': networkData['time_since_update'], - 'cumulativeRx': networkData['cumulative_rx'], - 'cumulativeTx': networkData['cumulative_tx'], - 'cumulativeCx': networkData['cumulative_cx'] - }; - - vm.networks.push(network); - } - - vm.networks = $filter('orderBy')(vm.networks, 'interfaceName'); - } -} - -'use strict'; - glancesApp.component('glancesPluginPorts', { controller: GlancesPluginPortsController, controllerAs: 'vm', @@ -1561,25 +1561,26 @@ function GlancesPluginProcessController(ARGUMENTS, hotkeys) { 'use strict'; -glancesApp.component('glancesPluginProcesscount', { - controller: GlancesPluginProcesscountController, +glancesApp.component('glancesPluginQuicklook', { + controller: GlancesPluginQuicklookController, controllerAs: 'vm', - bindings: { - sorter: '<' - }, - templateUrl: 'components/plugin-processcount/view.html' + templateUrl: 'components/plugin-quicklook/view.html' }); 'use strict'; -function GlancesPluginProcesscountController($scope, GlancesStats) { +function GlancesPluginQuicklookController($scope, GlancesStats, ARGUMENTS) { var vm = this; + vm.arguments = ARGUMENTS; + var _view = {}; - vm.total = null; - vm.running = null; - vm.sleeping = null; - vm.stopped = null; - vm.thread = null; + vm.mem = null; + vm.cpu = null; + vm.cpu_name = null; + vm.cpu_hz_current = null; + vm.cpu_hz = null; + vm.swap = null; + vm.percpus = []; vm.$onInit = function () { loadData(GlancesStats.getData()); @@ -1590,14 +1591,32 @@ function GlancesPluginProcesscountController($scope, GlancesStats) { }); var loadData = function (data) { - var processcountStats = data.stats['processcount']; + var stats = data.stats['quicklook']; + _view = data.views['quicklook']; - vm.total = processcountStats['total'] || 0; - vm.running = processcountStats['running'] || 0; - vm.sleeping = processcountStats['sleeping'] || 0; - vm.stopped = processcountStats['stopped'] || 0; - vm.thread = processcountStats['thread'] || 0; - } + vm.mem = stats.mem; + vm.cpu = stats.cpu; + vm.cpu_name = stats.cpu_name; + vm.cpu_hz_current = stats.cpu_hz_current; + vm.cpu_hz = stats.cpu_hz; + vm.swap = stats.swap; + vm.percpus = []; + + angular.forEach(stats.percpu, function (cpu) { + vm.percpus.push({ + 'number': cpu.cpu_number, + 'total': cpu.total + }); + }, this); + }; + + vm.getDecoration = function (value) { + if (_view[value] === undefined) { + return; + } + + return _view[value].decoration.toLowerCase(); + }; } 'use strict'; @@ -1689,26 +1708,25 @@ function GlancesPluginProcesslistController($scope, GlancesStats, GlancesPluginH 'use strict'; -glancesApp.component('glancesPluginQuicklook', { - controller: GlancesPluginQuicklookController, +glancesApp.component('glancesPluginProcesscount', { + controller: GlancesPluginProcesscountController, controllerAs: 'vm', - templateUrl: 'components/plugin-quicklook/view.html' + bindings: { + sorter: '<' + }, + templateUrl: 'components/plugin-processcount/view.html' }); 'use strict'; -function GlancesPluginQuicklookController($scope, GlancesStats, ARGUMENTS) { +function GlancesPluginProcesscountController($scope, GlancesStats) { var vm = this; - vm.arguments = ARGUMENTS; - var _view = {}; - vm.mem = null; - vm.cpu = null; - vm.cpu_name = null; - vm.cpu_hz_current = null; - vm.cpu_hz = null; - vm.swap = null; - vm.percpus = []; + vm.total = null; + vm.running = null; + vm.sleeping = null; + vm.stopped = null; + vm.thread = null; vm.$onInit = function () { loadData(GlancesStats.getData()); @@ -1719,31 +1737,60 @@ function GlancesPluginQuicklookController($scope, GlancesStats, ARGUMENTS) { }); var loadData = function (data) { - var stats = data.stats['quicklook']; - _view = data.views['quicklook']; + var processcountStats = data.stats['processcount']; - vm.mem = stats.mem; - vm.cpu = stats.cpu; - vm.cpu_name = stats.cpu_name; - vm.cpu_hz_current = stats.cpu_hz_current; - vm.cpu_hz = stats.cpu_hz; - vm.swap = stats.swap; - vm.percpus = []; + vm.total = processcountStats['total'] || 0; + vm.running = processcountStats['running'] || 0; + vm.sleeping = processcountStats['sleeping'] || 0; + vm.stopped = processcountStats['stopped'] || 0; + vm.thread = processcountStats['thread'] || 0; + } +} - angular.forEach(stats.percpu, function (cpu) { - vm.percpus.push({ - 'number': cpu.cpu_number, - 'total': cpu.total - }); - }, this); +'use strict'; + +glancesApp.component('glancesPluginSensors', { + controller: GlancesPluginSensorsController, + controllerAs: 'vm', + templateUrl: 'components/plugin-sensors/view.html' +}); + +'use strict'; + +function GlancesPluginSensorsController($scope, GlancesStats, GlancesPluginHelper, ARGUMENTS) { + var vm = this; + vm.sensors = []; + var convertToFahrenheit = ARGUMENTS.fahrenheit; + + vm.$onInit = function () { + loadData(GlancesStats.getData()); }; - vm.getDecoration = function (value) { - if (_view[value] === undefined) { - return; - } + $scope.$on('data_refreshed', function (event, data) { + loadData(data); + }); - return _view[value].decoration.toLowerCase(); + var loadData = function (data) { + var stats = data.stats['sensors']; + + _.remove(stats, function (sensor) { + return (_.isArray(sensor.value) && _.isEmpty(sensor.value)) || sensor.value === 0; + }); + + _.forEach(stats, function (sensor) { + if (convertToFahrenheit && sensor.type != 'battery' && sensor.type != 'fan_speed') { + sensor.value = parseFloat(sensor.value * 1.8 + 32).toFixed(1); + sensor.unit = 'F'; + } + }); + + vm.sensors = stats; + }; + + vm.getAlert = function (sensor) { + var current = sensor.type == 'battery' ? 100 - sensor.value : sensor.value; + + return GlancesPluginHelper.getAlert('sensors', 'sensors_' + sensor.type + '_', current); }; } @@ -1818,45 +1865,6 @@ function GlancesPluginRaidController($scope, GlancesStats) { 'use strict'; -glancesApp.component('glancesPluginSensors', { - controller: GlancesPluginSensorsController, - controllerAs: 'vm', - templateUrl: 'components/plugin-sensors/view.html' -}); - -'use strict'; - -function GlancesPluginSensorsController($scope, GlancesStats, GlancesPluginHelper) { - var vm = this; - vm.sensors = []; - - vm.$onInit = function () { - loadData(GlancesStats.getData()); - }; - - $scope.$on('data_refreshed', function (event, data) { - loadData(data); - }); - - var loadData = function (data) { - var stats = data.stats['sensors']; - - _.remove(stats, function (sensor) { - return (_.isArray(sensor.value) && _.isEmpty(sensor.value)) || sensor.value === 0; - }); - - vm.sensors = stats; - }; - - vm.getAlert = function (sensor) { - var current = sensor.type == 'battery' ? 100 - sensor.value : sensor.value; - - return GlancesPluginHelper.getAlert('sensors', 'sensors_' + sensor.type + '_', current); - }; -} - -'use strict'; - glancesApp.component('glancesPluginSystem', { controller: GlancesPluginSystemController, controllerAs: 'vm', @@ -1902,33 +1910,6 @@ function GlancesPluginSystemController($scope, GlancesStats) { 'use strict'; -glancesApp.component('glancesPluginUptime', { - controller: GlancesPluginUptimeController, - controllerAs: 'vm', - templateUrl: 'components/plugin-uptime/view.html' -}); - -'use strict'; - -function GlancesPluginUptimeController($scope, GlancesStats) { - var vm = this; - vm.value = null; - - vm.$onInit = function () { - loadData(GlancesStats.getData()); - }; - - $scope.$on('data_refreshed', function (event, data) { - loadData(data); - }); - - var loadData = function (data) { - vm.value = data.stats['uptime']; - } -} - -'use strict'; - glancesApp.component('glancesPluginWifi', { controller: GlancesPluginWifiController, controllerAs: 'vm', @@ -1983,3 +1964,30 @@ function GlancesPluginWifiController($scope, $filter, GlancesStats) { return _view[hotpost.ssid][field].decoration.toLowerCase(); }; } + +'use strict'; + +glancesApp.component('glancesPluginUptime', { + controller: GlancesPluginUptimeController, + controllerAs: 'vm', + templateUrl: 'components/plugin-uptime/view.html' +}); + +'use strict'; + +function GlancesPluginUptimeController($scope, GlancesStats) { + var vm = this; + vm.value = null; + + vm.$onInit = function () { + loadData(GlancesStats.getData()); + }; + + $scope.$on('data_refreshed', function (event, data) { + loadData(data); + }); + + var loadData = function (data) { + vm.value = data.stats['uptime']; + } +} diff --git a/glances/outputs/static/public/js/templates.min.js b/glances/outputs/static/public/js/templates.min.js index cf69ad53..3baf97dd 100644 --- a/glances/outputs/static/public/js/templates.min.js +++ b/glances/outputs/static/public/js/templates.min.js @@ -6,24 +6,24 @@ $templateCache.put('components/plugin-cloud/view.html','
\n $templateCache.put('components/plugin-cpu/view.html','
\n
\n
\n
\n
\n
CPU
\n
{{ vm.total }}%
\n
\n
\n
user:
\n
\n {{ vm.user }}%\n
\n
\n
\n
system:
\n
\n {{ vm.system }}%\n
\n
\n
\n
idle:
\n
{{ vm.idle }}%
\n
\n
\n
\n \n \n
\n
\n'); $templateCache.put('components/plugin-diskio/view.html','
\n
DISK I/O
\n
R/s
\n
W/s
\n\n
IOR/s
\n
IOW/s
\n
\n
\n
{{(disk.alias ? disk.alias : disk.name) | min_size:9}}
\n
{{disk.bitrate.txps }}
\n
{{disk.bitrate.rxps }}
\n\n
{{disk.count.txps }}
\n
{{disk.count.rxps }}
\n
\n'); $templateCache.put('components/plugin-docker/view.html','
\n CONTAINERS {{ vm.containers.length }} (served by Docker {{ vm.version }})\n\n
\n
\n
Name
\n
Status
\n
CPU%
\n
MEM
\n
IOR/s
\n
IOW/s
\n
RX/s
\n
TX/s
\n
Command
\n
\n
\n
{{ container.name }}
\n
{{ container.status }}\n
\n
{{ container.cpu | number:1 }}
\n
{{ container.memory | bytes }}
\n
{{ container.ior / container.io_time_since_update | bits }}
\n
{{ container.iow / container.io_time_since_update | bits }}
\n
{{ container.rx / container.net_time_since_update | bits }}
\n
{{ container.tx / container.net_time_since_update | bits }}
\n
{{ container.command }}
\n
\n
\n
\n'); -$templateCache.put('components/plugin-folders/view.html','
\n
FOLDERS
\n
Size
\n
\n
\n
{{ folder.path }}
\n
{{ folder.size | bytes }}
\n
\n'); $templateCache.put('components/plugin-fs/view.html','
\n
FILE SYS
\n
\n Used\n Free\n
\n
Total
\n
\n
\n
{{ fs.shortMountPoint }} ({{ fs.name }})\n
\n
\n {{ fs.used | bytes }}\n {{ fs.free | bytes }}\n
\n
{{ fs.size | bytes }}
\n
\n'); $templateCache.put('components/plugin-gpu/view.html','
\n
\n {{ vm.name }}\n
\n
\n
\n
proc:
\n
{{ vm.mean.proc |\n number : 0 }}%\n
\n
N/A
\n
\n
\n
mem:
\n
{{ vm.mean.mem | number :\n 0 }}%\n
\n
N/A
\n
\n
\n
\n {{ gpu.gpu_id }}:\n {{ gpu.proc | number : 0 }}%\n N/A\n mem:\n {{ gpu.mem | number : 0 }}%\n N/A\n
\n
\n
\n
\n'); +$templateCache.put('components/plugin-folders/view.html','
\n
FOLDERS
\n
Size
\n
\n
\n
{{ folder.path }}
\n
{{ folder.size | bytes }}
\n
\n'); $templateCache.put('components/plugin-ip/view.html','
\n  - IP {{ vm.address }}/{{ vm.maskCidr }} Pub {{ vm.publicAddress }}\n
\n'); $templateCache.put('components/plugin-irq/view.html','
\n
IRQ
\n
\n
Rate/s
\n
\n
\n
{{irq.irq_line}}
\n
\n
{{irq.irq_rate}}
\n
\n'); -$templateCache.put('components/plugin-load/view.html','
\n
\n
\n
LOAD
\n
{{ vm.cpucore }}-core
\n
\n
\n
1 min:
\n
\n {{ vm.min1 | number : 2}}\n
\n
\n
\n
5 min:
\n
\n {{ vm.min5 | number : 2}}\n
\n
\n
\n
15 min:
\n
\n {{ vm.min15 | number : 2}}\n
\n
\n
\n
\n'); $templateCache.put('components/plugin-mem/view.html','
\n
\n
\n
MEM
\n
{{ vm.percent }}%
\n
\n
\n
total:
\n
{{ vm.total | bytes }}
\n
\n
\n
used:
\n
\n {{ vm.used | bytes:2 }}\n
\n
\n
\n
free:
\n
{{ vm.free | bytes }}
\n
\n
\n
\n'); $templateCache.put('components/plugin-mem-more/view.html','
\n
\n
\n
active:
\n
{{ vm.active | bytes }}
\n
\n
\n
inactive:
\n
{{ vm.inactive | bytes }}
\n
\n
\n
buffers:
\n
{{ vm.buffers | bytes }}
\n
\n
\n
cached:
\n
{{ vm.cached | bytes }}
\n
\n
\n
\n'); +$templateCache.put('components/plugin-load/view.html','
\n
\n
\n
LOAD
\n
{{ vm.cpucore }}-core
\n
\n
\n
1 min:
\n
\n {{ vm.min1 | number : 2}}\n
\n
\n
\n
5 min:
\n
\n {{ vm.min5 | number : 2}}\n
\n
\n
\n
15 min:
\n
\n {{ vm.min15 | number : 2}}\n
\n
\n
\n
\n'); $templateCache.put('components/plugin-memswap/view.html','
\n
\n
\n
SWAP
\n
{{ vm.percent }}%
\n
\n
\n
total:
\n
{{ vm.total | bytes }}
\n
\n
\n
used:
\n
\n {{ vm.used | bytes }}\n
\n
\n
\n
free:
\n
{{ vm.free | bytes }}
\n
\n
\n
\n'); -$templateCache.put('components/plugin-percpu/view.html','
\n
\n
\n
PER CPU
\n
{{ percpu.total }}%
\n
\n
\n
user:
\n
\n {{ percpu.user }}%\n
\n
\n
\n
system:
\n
\n {{ percpu.system }}%\n
\n
\n
\n
idle:
\n
{{ percpu.idle }}%
\n
\n
\n
iowait:
\n
\n {{ percpu.iowait }}%\n
\n
\n
\n
steal:
\n
\n {{ percpu.steal }}%\n
\n
\n
\n
\n'); $templateCache.put('components/plugin-network/view.html','
\n
NETWORK
\n
Rx/s
\n
Tx/s
\n\n
\n
Rx+Tx/s
\n\n
Rx
\n
Tx
\n\n
\n
Rx+Tx
\n
\n
\n
{{ network.interfaceName | min_size }}
\n
{{ vm.arguments.byte ?\n (network.rx / network.time_since_update | bytes) : (network.rx / network.time_since_update | bits) }}\n
\n
{{ vm.arguments.byte ?\n (network.tx / network.time_since_update | bytes) : (network.tx / network.time_since_update | bits) }}\n
\n\n
\n
{{ vm.arguments.byte ?\n (network.cx / network.time_since_update | bytes) : (network.cx / network.time_since_update | bits) }}\n
\n\n
{{ vm.arguments.byte ?\n (network.cumulativeRx | bytes) : (network.cumulativeRx | bits) }}\n
\n
{{ vm.arguments.byte ?\n (network.cumulativeTx | bytes) : (network.cumulativeTx | bits) }}\n
\n\n
\n
{{ vm.arguments.byte ?\n (network.cumulativeCx | bytes) : (network.cumulativeCx | bits) }}\n
\n
\n'); +$templateCache.put('components/plugin-percpu/view.html','
\n
\n
\n
PER CPU
\n
{{ percpu.total }}%
\n
\n
\n
user:
\n
\n {{ percpu.user }}%\n
\n
\n
\n
system:
\n
\n {{ percpu.system }}%\n
\n
\n
\n
idle:
\n
{{ percpu.idle }}%
\n
\n
\n
iowait:
\n
\n {{ percpu.iowait }}%\n
\n
\n
\n
steal:
\n
\n {{ percpu.steal }}%\n
\n
\n
\n
\n'); $templateCache.put('components/plugin-ports/view.html','
\n
{{(port.description ? port.description : port.host + \' \' + port.port) | min_size:\n 20}}\n
\n
\n
\n Scanning\n Timeout\n Open\n {{port.status * 1000.0 | number:0}}ms\n
\n
'); $templateCache.put('components/plugin-process/view.html','
\n \n
\n
\n \n
\n
\n \n
\n
PROCESSES DISABLED (press \'z\' to display)
\n'); -$templateCache.put('components/plugin-processcount/view.html','
\n TASKS\n {{ vm.total }} ({{ vm.thread }} thr),\n {{ vm.running }} run,\n {{ vm.sleeping }} slp,\n {{ vm.stopped }} oth\n sorted {{ vm.sorter.auto ? \'automatically\' : \'\' }} by {{ vm.sorter.getColumnLabel(vm.sorter.column) }}, flat view\n
'); -$templateCache.put('components/plugin-processlist/view.html','
\n
\n
\n
CPU%
\n
MEM%
\n \n \n
PID
\n
USER
\n
NI
\n
S
\n \n \n \n
Command
\n
\n
\n
{{process.cpu_percent | number:1}}
\n
{{process.memory_percent | number:1}}\n
\n \n \n
{{process.pid}}
\n
{{process.username}}
\n
{{process.nice | exclamation}}
\n
{{process.status}}
\n \n \n \n
{{process.name}}
\n
{{process.cmdline}}
\n
\n
\n
\n'); $templateCache.put('components/plugin-quicklook/view.html','
\n
\n {{ vm.cpu_name }}\n
\n
\n
\n
CPU
\n
\n
\n
\n  \n
\n
\n
\n
\n {{ vm.cpu }}%\n
\n
\n
\n
CPU{{ percpu.number }}
\n
\n
\n
\n  \n
\n
\n
\n
\n {{ percpu.total }}%\n
\n
\n
\n
MEM
\n
\n
\n
\n  \n
\n
\n
\n
\n {{ vm.mem }}%\n
\n
\n
\n
SWAP
\n
\n
\n
\n  \n
\n
\n
\n
\n {{ vm.swap }}%\n
\n
\n
\n
\n'); -$templateCache.put('components/plugin-raid/view.html','
\n
RAID disks
\n
Used
\n
Total
\n
\n
\n
\n {{ disk.type | uppercase }} {{ disk.name }}\n
\u2514\u2500 Degraded mode
\n
   \u2514\u2500 {{ disk.config }}
\n\n
\u2514\u2500 Status {{ disk.status }}
\n
\n    {{ $last ? \'\u2514\u2500\' : \'\u251C\u2500\' }} disk {{ component.number }}: {{ component.name }}\n
\n
\n
{{ disk.used }}
\n
{{ disk.available }}
\n
\n'); +$templateCache.put('components/plugin-processlist/view.html','
\n
\n
\n
CPU%
\n
MEM%
\n \n \n
PID
\n
USER
\n
NI
\n
S
\n \n \n \n
Command
\n
\n
\n
{{process.cpu_percent | number:1}}
\n
{{process.memory_percent | number:1}}\n
\n \n \n
{{process.pid}}
\n
{{process.username}}
\n
{{process.nice | exclamation}}
\n
{{process.status}}
\n \n \n \n
{{process.name}}
\n
{{process.cmdline}}
\n
\n
\n
\n'); +$templateCache.put('components/plugin-processcount/view.html','
\n TASKS\n {{ vm.total }} ({{ vm.thread }} thr),\n {{ vm.running }} run,\n {{ vm.sleeping }} slp,\n {{ vm.stopped }} oth\n sorted {{ vm.sorter.auto ? \'automatically\' : \'\' }} by {{ vm.sorter.getColumnLabel(vm.sorter.column) }}, flat view\n
'); $templateCache.put('components/plugin-sensors/view.html','
\n
SENSORS
\n
\n\n
\n
{{ sensor.label }}
\n
{{ sensor.unit }}
\n
{{ sensor.value }}
\n
\n'); +$templateCache.put('components/plugin-raid/view.html','
\n
RAID disks
\n
Used
\n
Total
\n
\n
\n
\n {{ disk.type | uppercase }} {{ disk.name }}\n
\u2514\u2500 Degraded mode
\n
   \u2514\u2500 {{ disk.config }}
\n\n
\u2514\u2500 Status {{ disk.status }}
\n
\n    {{ $last ? \'\u2514\u2500\' : \'\u251C\u2500\' }} disk {{ component.number }}: {{ component.name }}\n
\n
\n
{{ disk.used }}
\n
{{ disk.available }}
\n
\n'); $templateCache.put('components/plugin-system/view.html','
\n Disconnected from\n {{ vm.hostname }}\n \n \n
\n'); -$templateCache.put('components/plugin-uptime/view.html','
\n Uptime: {{ vm.value }}\n
\n'); -$templateCache.put('components/plugin-wifi/view.html','
\n
WIFI
\n
\n
dBm
\n
\n
\n
{{ hotspot.ssid|limitTo:20 }} {{ hotspot.encryption_type }}\n
\n
\n
{{ hotspot.signal }}
\n
\n');}]); \ No newline at end of file +$templateCache.put('components/plugin-wifi/view.html','
\n
WIFI
\n
\n
dBm
\n
\n
\n
{{ hotspot.ssid|limitTo:20 }} {{ hotspot.encryption_type }}\n
\n
\n
{{ hotspot.signal }}
\n
\n'); +$templateCache.put('components/plugin-uptime/view.html','
\n Uptime: {{ vm.value }}\n
\n');}]); \ No newline at end of file diff --git a/glances/outputs/static/public/js/vendor.min.js b/glances/outputs/static/public/js/vendor.min.js index 8b58ec86..3c7b7ec1 100644 --- a/glances/outputs/static/public/js/vendor.min.js +++ b/glances/outputs/static/public/js/vendor.min.js @@ -1,5 +1,5 @@ /** - * @license AngularJS v1.6.6 + * @license AngularJS v1.6.7 * (c) 2010-2017 Google, Inc. http://angularjs.org * License: MIT */ @@ -106,7 +106,7 @@ function minErr(module, ErrorConstructor) { return match; }); - message += '\nhttp://errors.angularjs.org/1.6.6/' + + message += '\nhttp://errors.angularjs.org/1.6.7/' + (module ? module + '/' : '') + code; for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') { @@ -229,13 +229,11 @@ function minErr(module, ErrorConstructor) { * @installation * @description * - * # ng (core module) * The ng module is loaded by default when an AngularJS application is started. The module itself * contains the essential components for an AngularJS application to function. The table below * lists a high level breakdown of each of the services/factories, filters, directives and testing * components available within this core module. * - *
*/ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/; @@ -976,7 +974,7 @@ function arrayRemove(array, value) {
form = {{user | json}}
-
master = {{master | json}}
+
leader = {{leader | json}}
@@ -984,16 +982,16 @@ function arrayRemove(array, value) { angular. module('copyExample', []). controller('ExampleController', ['$scope', function($scope) { - $scope.master = {}; + $scope.leader = {}; $scope.reset = function() { // Example with 1 argument - $scope.user = angular.copy($scope.master); + $scope.user = angular.copy($scope.leader); }; $scope.update = function(user) { // Example with 2 arguments - angular.copy(user, $scope.master); + angular.copy(user, $scope.leader); }; $scope.reset(); @@ -1729,6 +1727,10 @@ var isAutoBootstrapAllowed = allowAutoBootstrap(window.document); * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}` * would not be resolved to `3`. * + * @example + * + * ### Simple Usage + * * `ngApp` is the easiest, and most common way to bootstrap an application. * @@ -1745,6 +1747,10 @@ var isAutoBootstrapAllowed = allowAutoBootstrap(window.document); * + * @example + * + * ### With `ngStrictDi` + * * Using `ngStrictDi`, you would see something like this: * @@ -2784,11 +2790,11 @@ function toDebugString(obj, maxDepth) { var version = { // These placeholder strings will be replaced by grunt's `build` task. // They need to be double- or single-quoted. - full: '1.6.6', + full: '1.6.7', major: 1, minor: 6, - dot: 6, - codeName: 'interdimensional-cable' + dot: 7, + codeName: 'imperial-backstroke' }; @@ -2934,7 +2940,7 @@ function publishExternalAPI(angular) { }); } ]) - .info({ angularVersion: '1.6.6' }); + .info({ angularVersion: '1.6.7' }); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * @@ -3357,13 +3363,18 @@ function jqLiteHasClass(element, selector) { function jqLiteRemoveClass(element, cssClasses) { if (cssClasses && element.setAttribute) { + var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ') + .replace(/[\n\t]/g, ' '); + var newClasses = existingClasses; + forEach(cssClasses.split(' '), function(cssClass) { - element.setAttribute('class', trim( - (' ' + (element.getAttribute('class') || '') + ' ') - .replace(/[\n\t]/g, ' ') - .replace(' ' + trim(cssClass) + ' ', ' ')) - ); + cssClass = trim(cssClass); + newClasses = newClasses.replace(' ' + cssClass + ' ', ' '); }); + + if (newClasses !== existingClasses) { + element.setAttribute('class', trim(newClasses)); + } } } @@ -3371,15 +3382,18 @@ function jqLiteAddClass(element, cssClasses) { if (cssClasses && element.setAttribute) { var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ') .replace(/[\n\t]/g, ' '); + var newClasses = existingClasses; forEach(cssClasses.split(' '), function(cssClass) { cssClass = trim(cssClass); - if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) { - existingClasses += cssClass + ' '; + if (newClasses.indexOf(' ' + cssClass + ' ') === -1) { + newClasses += cssClass + ' '; } }); - element.setAttribute('class', trim(existingClasses)); + if (newClasses !== existingClasses) { + element.setAttribute('class', trim(newClasses)); + } } } @@ -4287,7 +4301,7 @@ function annotate(fn, strictDi, name) { * })).toBe($injector); * ``` * - * # Injection Function Annotation + * ## Injection Function Annotation * * JavaScript does not have annotations, and annotations are needed for dependency injection. The * following are all valid ways of annotating function with injection arguments and are equivalent. @@ -4305,7 +4319,7 @@ function annotate(fn, strictDi, name) { * $injector.invoke(['serviceA', function(serviceA){}]); * ``` * - * ## Inference + * ### Inference * * In JavaScript calling `toString()` on a function returns the function definition. The definition * can then be parsed and the function arguments can be extracted. This method of discovering @@ -4313,10 +4327,10 @@ function annotate(fn, strictDi, name) { * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the * argument names. * - * ## `$inject` Annotation + * ### `$inject` Annotation * By adding an `$inject` property onto a function the injection parameters can be specified. * - * ## Inline + * ### Inline * As an array of injection names, where the last item in the array is the function to call. */ @@ -4404,7 +4418,7 @@ function annotate(fn, strictDi, name) { * function is invoked. There are three ways in which the function can be annotated with the needed * dependencies. * - * # Argument names + * #### Argument names * * The simplest form is to extract the dependencies from the arguments of the function. This is done * by converting the function into a string using `toString()` method and extracting the argument @@ -4424,7 +4438,7 @@ function annotate(fn, strictDi, name) { * This method does not work with code minification / obfuscation. For this reason the following * annotation strategies are supported. * - * # The `$inject` property + * #### The `$inject` property * * If a function has an `$inject` property and its value is an array of strings, then the strings * represent names of services to be injected into the function. @@ -4440,7 +4454,7 @@ function annotate(fn, strictDi, name) { * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); * ``` * - * # The array notation + * #### The array notation * * It is often desirable to inline Injected functions and that's when setting the `$inject` property * is very inconvenient. In these situations using the array notation to specify the dependencies in @@ -4477,7 +4491,45 @@ function annotate(fn, strictDi, name) { * * @returns {Array.} The names of the services which the function requires. */ - +/** + * @ngdoc method + * @name $injector#loadNewModules + * + * @description + * + * **This is a dangerous API, which you use at your own risk!** + * + * Add the specified modules to the current injector. + * + * This method will add each of the injectables to the injector and execute all of the config and run + * blocks for each module passed to the method. + * + * If a module has already been loaded into the injector then it will not be loaded again. + * + * * The application developer is responsible for loading the code containing the modules; and for + * ensuring that lazy scripts are not downloaded and executed more often that desired. + * * Previously compiled HTML will not be affected by newly loaded directives, filters and components. + * * Modules cannot be unloaded. + * + * You can use {@link $injector#modules `$injector.modules`} to check whether a module has been loaded + * into the injector, which may indicate whether the script has been executed already. + * + * @example + * Here is an example of loading a bundle of modules, with a utility method called `getScript`: + * + * ```javascript + * app.factory('loadModule', function($injector) { + * return function loadModule(moduleName, bundleUrl) { + * return getScript(bundleUrl).then(function() { $injector.loadNewModules([moduleName]); }); + * }; + * }) + * ``` + * + * @param {Array=} mods an array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a `config` block. + * See: {@link angular.module modules} + */ /** @@ -4841,6 +4893,11 @@ function createInjector(modulesToLoad, strictDi) { instanceInjector.strictDi = strictDi; forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); }); + instanceInjector.loadNewModules = function(mods) { + forEach(loadModules(mods), function(fn) { if (fn) instanceInjector.invoke(fn); }); + }; + + return instanceInjector; //////////////////////////////////// @@ -6782,8 +6839,8 @@ function $CacheFactoryProvider() { * * @description * A cache object used to store and retrieve data, primarily used by - * {@link $http $http} and the {@link ng.directive:script script} directive to cache - * templates and other data. + * {@link $templateRequest $templateRequest} and the {@link ng.directive:script script} + * directive to cache templates and other data. * * ```js * angular.module('superCache') @@ -7036,9 +7093,12 @@ function $CacheFactoryProvider() { * @this * * @description + * `$templateCache` is a {@link $cacheFactory.Cache Cache object} created by the + * {@link ng.$cacheFactory $cacheFactory}. + * * The first time a template is used, it is loaded in the template cache for quick retrieval. You - * can load templates directly into the cache in a `script` tag, or by consuming the - * `$templateCache` service directly. + * can load templates directly into the cache in a `script` tag, by using {@link $templateRequest}, + * or by consuming the `$templateCache` service directly. * * Adding via the `script` tag: * @@ -7049,8 +7109,8 @@ function $CacheFactoryProvider() { * ``` * * **Note:** the `script` tag containing the template does not need to be included in the `head` of - * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE, - * element with ng-app attribute), otherwise the template will be ignored. + * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (e.g. + * element with {@link ngApp} attribute), otherwise the template will be ignored. * * Adding via the `$templateCache` service: * @@ -7073,8 +7133,6 @@ function $CacheFactoryProvider() { * $templateCache.get('templateId.html') * ``` * - * See {@link ng.$cacheFactory $cacheFactory}. - * */ function $TemplateCacheProvider() { this.$get = ['$cacheFactory', function($cacheFactory) { @@ -7588,8 +7646,11 @@ function $TemplateCacheProvider() { * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}. * * - * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0) - * specify what the template should replace. Defaults to `false`. + * #### `replace` (*DEPRECATED*) + * + * `replace` will be removed in next major release - i.e. v2.0). + * + * Specifies what the template should replace. Defaults to `false`. * * * `true` - the template will replace the directive's element. * * `false` - the template will replace the contents of the directive's element. @@ -8444,7 +8505,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { * binding information and a reference to the current scope on to DOM elements. * If enabled, the compiler will add the following to DOM elements that have been bound to the scope * * `ng-binding` CSS class + * * `ng-scope` and `ng-isolated-scope` CSS classes * * `$binding` data property containing an array of the binding expressions + * * Data properties used by the {@link angular.element#methods `scope()`/`isolateScope()` methods} to return + * the element's scope. + * * Placeholder comments will contain information about what directive and binding caused the placeholder. + * E.g. ``. * * You may want to disable this in production for a significant performance boost. See * {@link guide/production#disabling-debug-data Disabling Debug Data} for more. @@ -10745,7 +10811,9 @@ var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g; function directiveNormalize(name) { return name .replace(PREFIX_REGEXP, '') - .replace(SPECIAL_CHARS_REGEXP, fnCamelCaseReplace); + .replace(SPECIAL_CHARS_REGEXP, function(_, letter, offset) { + return offset ? letter.toUpperCase() : letter; + }); } /** @@ -12266,7 +12334,7 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object + * @param {Object=} config Optional configuration object. See https://docs.angularjs.org/api/ng/service/$http#usage * @returns {HttpPromise} Future object */ @@ -12279,7 +12347,7 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object + * @param {Object=} config Optional configuration object. See https://docs.angularjs.org/api/ng/service/$http#usage * @returns {HttpPromise} Future object */ @@ -12292,7 +12360,7 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object + * @param {Object=} config Optional configuration object. See https://docs.angularjs.org/api/ng/service/$http#usage * @returns {HttpPromise} Future object */ @@ -12309,6 +12377,10 @@ function $HttpProvider() { * {@link $sceDelegateProvider#resourceUrlWhitelist `$sceDelegateProvider.resourceUrlWhitelist`} or * by explicitly trusting the URL via {@link $sce#trustAsResourceUrl `$sce.trustAsResourceUrl(url)`}. * + * You should avoid generating the URL for the JSONP request from user provided data. + * Provide additional query parameters via `params` property of the `config` parameter, rather than + * modifying the URL itself. + * * JSONP requests must specify a callback to be used in the response from the server. This callback * is passed as a query parameter in the request. You must specify the name of this parameter by * setting the `jsonpCallbackParam` property on the request config object. @@ -12330,7 +12402,7 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object + * @param {Object=} config Optional configuration object. See https://docs.angularjs.org/api/ng/service/$http#usage * @returns {HttpPromise} Future object */ createShortMethods('get', 'delete', 'head', 'jsonp'); @@ -12344,7 +12416,7 @@ function $HttpProvider() { * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content - * @param {Object=} config Optional configuration object + * @param {Object=} config Optional configuration object. See https://docs.angularjs.org/api/ng/service/$http#usage * @returns {HttpPromise} Future object */ @@ -12357,7 +12429,7 @@ function $HttpProvider() { * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content - * @param {Object=} config Optional configuration object + * @param {Object=} config Optional configuration object. See https://docs.angularjs.org/api/ng/service/$http#usage * @returns {HttpPromise} Future object */ @@ -12370,7 +12442,7 @@ function $HttpProvider() { * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content - * @param {Object=} config Optional configuration object + * @param {Object=} config Optional configuration object. See https://docs.angularjs.org/api/ng/service/$http#usage * @returns {HttpPromise} Future object */ createShortMethodsWithData('post', 'put', 'patch'); @@ -12584,20 +12656,26 @@ function $HttpProvider() { return url; } - function sanitizeJsonpCallbackParam(url, key) { - if (/[&?][^=]+=JSON_CALLBACK/.test(url)) { - // Throw if the url already contains a reference to JSON_CALLBACK - throw $httpMinErr('badjsonp', 'Illegal use of JSON_CALLBACK in url, "{0}"', url); - } - - var callbackParamRegex = new RegExp('[&?]' + key + '='); - if (callbackParamRegex.test(url)) { - // Throw if the callback param was already provided - throw $httpMinErr('badjsonp', 'Illegal use of callback param, "{0}", in url, "{1}"', key, url); + function sanitizeJsonpCallbackParam(url, cbKey) { + var parts = url.split('?'); + if (parts.length > 2) { + // Throw if the url contains more than one `?` query indicator + throw $httpMinErr('badjsonp', 'Illegal use more than one "?", in url, "{1}"', url); } + var params = parseKeyValue(parts[1]); + forEach(params, function(value, key) { + if (value === 'JSON_CALLBACK') { + // Throw if the url already contains a reference to JSON_CALLBACK + throw $httpMinErr('badjsonp', 'Illegal use of JSON_CALLBACK in url, "{0}"', url); + } + if (key === cbKey) { + // Throw if the callback param was already provided + throw $httpMinErr('badjsonp', 'Illegal use of callback param, "{0}", in url, "{1}"', cbKey, url); + } + }); // Add in the JSON_CALLBACK callback param value - url += ((url.indexOf('?') === -1) ? '?' : '&') + key + '=JSON_CALLBACK'; + url += ((url.indexOf('?') === -1) ? '?' : '&') + cbKey + '=JSON_CALLBACK'; return url; } @@ -13523,7 +13601,23 @@ function encodePath(path) { i = segments.length; while (i--) { - segments[i] = encodeUriSegment(segments[i]); + // decode forward slashes to prevent them from being double encoded + segments[i] = encodeUriSegment(segments[i].replace(/%2F/g, '/')); + } + + return segments.join('/'); +} + +function decodePath(path, html5Mode) { + var segments = path.split('/'), + i = segments.length; + + while (i--) { + segments[i] = decodeURIComponent(segments[i]); + if (html5Mode) { + // encode forward slashes to prevent them from being mistaken for path separators + segments[i] = segments[i].replace(/\//g, '%2F'); + } } return segments.join('/'); @@ -13538,7 +13632,7 @@ function parseAbsoluteUrl(absoluteUrl, locationObj) { } var DOUBLE_SLASH_REGEX = /^\s*[\\/]{2,}/; -function parseAppUrl(url, locationObj) { +function parseAppUrl(url, locationObj, html5Mode) { if (DOUBLE_SLASH_REGEX.test(url)) { throw $locationMinErr('badpath', 'Invalid url "{0}".', url); @@ -13549,8 +13643,8 @@ function parseAppUrl(url, locationObj) { url = '/' + url; } var match = urlResolve(url); - locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? - match.pathname.substring(1) : match.pathname); + var path = prefixed && match.pathname.charAt(0) === '/' ? match.pathname.substring(1) : match.pathname; + locationObj.$$path = decodePath(path, html5Mode); locationObj.$$search = parseKeyValue(match.search); locationObj.$$hash = decodeURIComponent(match.hash); @@ -13625,7 +13719,7 @@ function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) { appBaseNoFile); } - parseAppUrl(pathUrl, this); + parseAppUrl(pathUrl, this, true); if (!this.$$path) { this.$$path = '/'; @@ -13728,7 +13822,7 @@ function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) { } } - parseAppUrl(withoutHashUrl, this); + parseAppUrl(withoutHashUrl, this, false); this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase); @@ -13913,7 +14007,7 @@ var locationPrototype = { } var match = PATH_MATCH.exec(url); - if (match[1] || url === '') this.path(decodeURIComponent(match[1])); + if (match[1] || url === '') this.path(decodeURI(match[1])); if (match[2] || match[1] || url === '') this.search(match[3] || ''); this.hash(match[5] || ''); @@ -16707,7 +16801,7 @@ function $ParseProvider() { * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred * implementations, and the other which resembles ES6 (ES2015) promises to some degree. * - * # $q constructor + * ## $q constructor * * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver` * function as the first argument. This is similar to the native Promise implementation from ES6, @@ -16795,7 +16889,7 @@ function $ParseProvider() { * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the * section on serial or parallel joining of promises. * - * # The Deferred API + * ## The Deferred API * * A new instance of deferred is constructed by calling `$q.defer()`. * @@ -16817,7 +16911,7 @@ function $ParseProvider() { * - promise – `{Promise}` – promise object associated with this deferred. * * - * # The Promise API + * ## The Promise API * * A new promise instance is created when a deferred instance is created and can be retrieved by * calling `deferred.promise`. @@ -16849,7 +16943,7 @@ function $ParseProvider() { * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for * more information. * - * # Chaining promises + * ## Chaining promises * * Because calling the `then` method of a promise returns a new derived promise, it is easily * possible to create a chain of promises: @@ -16869,7 +16963,7 @@ function $ParseProvider() { * $http's response interceptors. * * - * # Differences between Kris Kowal's Q and $q + * ## Differences between Kris Kowal's Q and $q * * There are two main differences: * @@ -16879,7 +16973,7 @@ function $ParseProvider() { * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains * all the important functionality needed for common async tasks. * - * # Testing + * ## Testing * * ```js * it('should simulate promise', inject(function($q, $rootScope) { @@ -17056,6 +17150,10 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { } } catch (e) { rejectPromise(promise, e); + // This error is explicitly marked for being passed to the $exceptionHandler + if (e && e.$$passToExceptionHandler === true) { + exceptionHandler(e); + } } } } finally { @@ -17548,7 +17646,7 @@ function $RootScopeProvider() { * an in-depth introduction and usage examples. * * - * # Inheritance + * ## Inheritance * A scope can inherit from a parent scope, as in this example: * ```js var parent = $rootScope; @@ -17723,7 +17821,7 @@ function $RootScopeProvider() { * * * - * # Example + * @example * ```js // let's assume that scope was dependency injected as the $rootScope var scope = $rootScope; @@ -17974,7 +18072,7 @@ function $RootScopeProvider() { * adding, removing, and moving items belonging to an object or array. * * - * # Example + * @example * ```js $scope.names = ['igor', 'matias', 'misko', 'james']; $scope.dataCount = 4; @@ -18172,7 +18270,7 @@ function $RootScopeProvider() { * * In unit tests, you may need to call `$digest()` to simulate the scope life cycle. * - * # Example + * @example * ```js var scope = ...; scope.name = 'misko'; @@ -18401,7 +18499,7 @@ function $RootScopeProvider() { * the expression are propagated (uncaught). This is useful when evaluating Angular * expressions. * - * # Example + * @example * ```js var scope = ng.$rootScope.Scope(); scope.a = 1; @@ -18483,9 +18581,8 @@ function $RootScopeProvider() { * cycle of {@link ng.$exceptionHandler exception handling}, * {@link ng.$rootScope.Scope#$digest executing watches}. * - * ## Life cycle + * **Life cycle: Pseudo-Code of `$apply()`** * - * # Pseudo-Code of `$apply()` * ```js function $apply(expr) { try { @@ -18613,7 +18710,10 @@ function $RootScopeProvider() { return function() { var indexOfListener = namedListeners.indexOf(listener); if (indexOfListener !== -1) { - namedListeners[indexOfListener] = null; + // Use delete in the hope of the browser deallocating the memory for the array entry, + // while not shifting the array indexes of other listeners. + // See issue https://github.com/angular/angular.js/issues/16135 + delete namedListeners[indexOfListener]; decrementListenerCount(self, 1, name); } }; @@ -18680,8 +18780,7 @@ function $RootScopeProvider() { } //if any listener on the current scope stops propagation, prevent bubbling if (stopPropagation) { - event.currentScope = null; - return event; + break; } //traverse upwards scope = scope.$parent; @@ -18857,7 +18956,7 @@ function $RootScopeProvider() { * Private service to sanitize uris for links and images. Used by $compile and $sanitize. */ function $$SanitizeUriProvider() { - var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/, + var aHrefSanitizationWhitelist = /^\s*(https?|s?ftp|mailto|tel|file):/, imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/; /** @@ -18913,7 +19012,7 @@ function $$SanitizeUriProvider() { return function sanitizeUri(uri, isImage) { var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist; var normalizedVal; - normalizedVal = urlResolve(uri).href; + normalizedVal = urlResolve(uri && uri.trim()).href; if (normalizedVal !== '' && !normalizedVal.match(regex)) { return 'unsafe:' + normalizedVal; } @@ -19385,13 +19484,13 @@ function $SceDelegateProvider() { * * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS. * - * # Strict Contextual Escaping + * ## Strict Contextual Escaping * * Strict Contextual Escaping (SCE) is a mode in which AngularJS constrains bindings to only render * trusted values. Its goal is to assist in writing code in a way that (a) is secure by default, and * (b) makes auditing for security vulnerabilities such as XSS, clickjacking, etc. a lot easier. * - * ## Overview + * ### Overview * * To systematically block XSS security bugs, AngularJS treats all values as untrusted by default in * HTML or sensitive URL bindings. When binding untrusted values, AngularJS will automatically @@ -19407,7 +19506,7 @@ function $SceDelegateProvider() { * * As of version 1.2, AngularJS ships with SCE enabled by default. * - * ## In practice + * ### In practice * * Here's an example of a binding in a privileged context: * @@ -19444,7 +19543,7 @@ function $SceDelegateProvider() { * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to * build the trusted versions of your values. * - * ## How does it work? + * ### How does it work? * * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted * $sce.getTrusted(context, value)} rather than to the value directly. Think of this function as @@ -19468,7 +19567,7 @@ function $SceDelegateProvider() { * }]; * ``` * - * ## Impact on loading templates + * ### Impact on loading templates * * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as * `templateUrl`'s specified by {@link guide/directive directives}. @@ -19488,7 +19587,7 @@ function $SceDelegateProvider() { * won't work on all browsers. Also, loading templates from `file://` URL does not work on some * browsers. * - * ## This feels like too much overhead + * ### This feels like too much overhead * * It's important to remember that SCE only applies to interpolation expressions. * @@ -19512,7 +19611,7 @@ function $SceDelegateProvider() { * security onto an application later. * * - * ## What trusted context types are supported? + * ### What trusted context types are supported? * * | Context | Notes | * |---------------------|----------------| @@ -19528,7 +19627,7 @@ function $SceDelegateProvider() { * in AngularJS currently, so their corresponding `$sce.trustAs` functions aren't useful yet. This * might evolve. * - * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} + * ### Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} * * Each element in these arrays must be one of the following: * @@ -19575,7 +19674,7 @@ function $SceDelegateProvider() { * * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example. * - * ## Show me an example using SCE. + * ### Show me an example using SCE. * * * @@ -20205,6 +20304,12 @@ function $TemplateRequestProvider() { * If you want to pass custom options to the `$http` service, such as setting the Accept header you * can configure this via {@link $templateRequestProvider#httpOptions}. * + * `$templateRequest` is used internally by {@link $compile}, {@link ngRoute.$route}, and directives such + * as {@link ngInclude} to download and cache templates. + * + * 3rd party modules should use `$templateRequest` if their services or directives are loading + * templates. + * * @param {string|TrustedResourceUrl} tpl The HTTP request template URL * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty * @@ -22935,14 +23040,14 @@ var htmlAnchorDirective = valueFn({ * @example -
- +
+
it('should check both checkBoxes', function() { - expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy(); - element(by.model('master')).click(); - expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy(); + expect(element(by.id('checkFollower')).getAttribute('checked')).toBeFalsy(); + element(by.model('leader')).click(); + expect(element(by.id('checkFollower')).getAttribute('checked')).toBeTruthy(); });
@@ -23537,7 +23642,7 @@ addSetValidityMethod({ * If the `name` attribute is specified, the form controller is published onto the current scope under * this name. * - * # Alias: {@link ng.directive:ngForm `ngForm`} + * ## Alias: {@link ng.directive:ngForm `ngForm`} * * In Angular, forms can be nested. This means that the outer form is valid when all of the child * forms are valid as well. However, browsers do not allow nesting of `
` elements, so @@ -23545,7 +23650,7 @@ addSetValidityMethod({ * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group * of controls needs to be determined. * - * # CSS classes + * ## CSS classes * - `ng-valid` is set if the form is valid. * - `ng-invalid` is set if the form is invalid. * - `ng-pending` is set if the form is pending. @@ -23556,7 +23661,7 @@ addSetValidityMethod({ * Keep in mind that ngAnimate can detect each of these classes when added and removed. * * - * # Submitting a form and preventing the default action + * ## Submitting a form and preventing the default action * * Since the role of forms in client-side Angular applications is different than in classical * roundtrip apps, it is desirable for the browser not to translate the form submission into a full @@ -23589,8 +23694,7 @@ addSetValidityMethod({ * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit` * to have access to the updated model. * - * ## Animation Hooks - * + * @animations * Animations in ngForm are triggered when any of the associated CSS classes are added and removed. * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any * other validations that are performed within the form. Animations in ngForm are similar to how @@ -24953,8 +25057,8 @@ var inputType = { * Can be interpolated. * @param {string=} step Sets the `step` validation to ensure that the value entered matches the `step` * Can be interpolated. - * @param {string=} ngChange Angular expression to be executed when the ngModel value changes due - * to user interaction with the input element. + * @param {expression=} ngChange AngularJS expression to be executed when the ngModel value changes due + * to user interaction with the input element. * @param {expression=} ngChecked If the expression is truthy, then the `checked` attribute will be set on the * element. **Note** : `ngChecked` should not be used alongside `ngModel`. * Checkout {@link ng.directive:ngChecked ngChecked} for usage. @@ -25939,6 +26043,8 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/; /** * @ngdoc directive * @name ngValue + * @restrict A + * @priority 100 * * @description * Binds the given expression to the value of the element. @@ -25951,8 +26057,8 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/; * It can also be used to achieve one-way binding of a given expression to an input element * such as an `input[text]` or a `textarea`, when that element does not use ngModel. * - * @element input - * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute + * @element ANY + * @param {string=} ngValue AngularJS expression, whose value will be bound to the `value` attribute * and `value` property of the element. * * @example @@ -26236,6 +26342,7 @@ var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, /** * @ngdoc directive * @name ngChange + * @restrict A * * @description * Evaluate the given expression when the user changes the input. @@ -26254,7 +26361,7 @@ var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, * * Note, this directive requires `ngModel` to be present. * - * @element input + * @element ANY * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change * in input value. * @@ -26496,6 +26603,7 @@ function classDirective(name, selector) { * @ngdoc directive * @name ngClass * @restrict AC + * @element ANY * * @description * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding @@ -26531,14 +26639,21 @@ function classDirective(name, selector) { * | {@link ng.$animate#addClass addClass} | just before the class is applied to the element | * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element | * - * @element ANY + * ### ngClass and pre-existing CSS3 Transitions/Animations + The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure. + Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder + any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure + to view the step by step details of {@link $animate#addClass $animate.addClass} and + {@link $animate#removeClass $animate.removeClass}. + * * @param {expression} ngClass {@link guide/expression Expression} to eval. The result * of the evaluation can be a string representing space delimited class * names, an array, or a map of class names to boolean values. In the case of a map, the * names of the properties whose values are truthy will be added as css classes to the * element. * - * @example Example that demonstrates basic bindings via ngClass directive. + * @example + * ### Basic

Map Syntax Example

@@ -26628,7 +26743,8 @@ function classDirective(name, selector) {
- ## Animations + @example + ### Animations The example below demonstrates how to perform animations using ngClass. @@ -26666,14 +26782,6 @@ function classDirective(name, selector) { }); - - - ## ngClass and pre-existing CSS3 Transitions/Animations - The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure. - Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder - any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure - to view the step by step details of {@link $animate#addClass $animate.addClass} and - {@link $animate#removeClass $animate.removeClass}. */ var ngClassDirective = classDirective('', true); @@ -27147,6 +27255,7 @@ var ngControllerDirective = [function() { * E.g.`` * * @example + * * This example shows how to apply the `ngCsp` directive to the `html` tag. ```html @@ -27155,122 +27264,122 @@ var ngControllerDirective = [function() { ... ``` - * @example - - - -
-
- - - {{ctrl.counter}} - -
-
- - - {{ctrl.evilError}} - -
-
-
- - angular.module('cspExample', []) - .controller('MainController', function MainController() { - this.counter = 0; - this.inc = function() { - this.counter++; - }; - this.evil = function() { - try { - eval('1+2'); // eslint-disable-line no-eval - } catch (e) { - this.evilError = e.message; - } - }; - }); - - - var util, webdriver; + + + +
+
+ + + {{ctrl.counter}} + +
- var incBtn = element(by.id('inc')); - var counter = element(by.id('counter')); - var evilBtn = element(by.id('evil')); - var evilError = element(by.id('evilError')); - - function getAndClearSevereErrors() { - return browser.manage().logs().get('browser').then(function(browserLog) { - return browserLog.filter(function(logEntry) { - return logEntry.level.value > webdriver.logging.Level.WARNING.value; - }); - }); - } - - function clearErrors() { - getAndClearSevereErrors(); - } - - function expectNoErrors() { - getAndClearSevereErrors().then(function(filteredLog) { - expect(filteredLog.length).toEqual(0); - if (filteredLog.length) { - console.log('browser console errors: ' + util.inspect(filteredLog)); +
+ + + {{ctrl.evilError}} + +
+
+
+ + angular.module('cspExample', []) + .controller('MainController', function MainController() { + this.counter = 0; + this.inc = function() { + this.counter++; + }; + this.evil = function() { + try { + eval('1+2'); // eslint-disable-line no-eval + } catch (e) { + this.evilError = e.message; } - }); + }; + }); + + + var util, webdriver; + + var incBtn = element(by.id('inc')); + var counter = element(by.id('counter')); + var evilBtn = element(by.id('evil')); + var evilError = element(by.id('evilError')); + + function getAndClearSevereErrors() { + return browser.manage().logs().get('browser').then(function(browserLog) { + return browserLog.filter(function(logEntry) { + return logEntry.level.value > webdriver.logging.Level.WARNING.value; + }); + }); + } + + function clearErrors() { + getAndClearSevereErrors(); + } + + function expectNoErrors() { + getAndClearSevereErrors().then(function(filteredLog) { + expect(filteredLog.length).toEqual(0); + if (filteredLog.length) { + console.log('browser console errors: ' + util.inspect(filteredLog)); } + }); + } - function expectError(regex) { - getAndClearSevereErrors().then(function(filteredLog) { - var found = false; - filteredLog.forEach(function(log) { - if (log.message.match(regex)) { - found = true; - } - }); - if (!found) { - throw new Error('expected an error that matches ' + regex); - } - }); + function expectError(regex) { + getAndClearSevereErrors().then(function(filteredLog) { + var found = false; + filteredLog.forEach(function(log) { + if (log.message.match(regex)) { + found = true; + } + }); + if (!found) { + throw new Error('expected an error that matches ' + regex); } + }); + } - beforeEach(function() { - util = require('util'); - webdriver = require('selenium-webdriver'); - }); + beforeEach(function() { + util = require('util'); + webdriver = require('selenium-webdriver'); + }); - // For now, we only test on Chrome, - // as Safari does not load the page with Protractor's injected scripts, - // and Firefox webdriver always disables content security policy (#6358) - if (browser.params.browser !== 'chrome') { - return; - } + // For now, we only test on Chrome, + // as Safari does not load the page with Protractor's injected scripts, + // and Firefox webdriver always disables content security policy (#6358) + if (browser.params.browser !== 'chrome') { + return; + } - it('should not report errors when the page is loaded', function() { - // clear errors so we are not dependent on previous tests - clearErrors(); - // Need to reload the page as the page is already loaded when - // we come here - browser.driver.getCurrentUrl().then(function(url) { - browser.get(url); - }); - expectNoErrors(); - }); + it('should not report errors when the page is loaded', function() { + // clear errors so we are not dependent on previous tests + clearErrors(); + // Need to reload the page as the page is already loaded when + // we come here + browser.driver.getCurrentUrl().then(function(url) { + browser.get(url); + }); + expectNoErrors(); + }); - it('should evaluate expressions', function() { - expect(counter.getText()).toEqual('0'); - incBtn.click(); - expect(counter.getText()).toEqual('1'); - expectNoErrors(); - }); + it('should evaluate expressions', function() { + expect(counter.getText()).toEqual('0'); + incBtn.click(); + expect(counter.getText()).toEqual('1'); + expectNoErrors(); + }); - it('should throw and report an error when using "eval"', function() { - evilBtn.click(); - expect(evilError.getText()).toMatch(/Content Security Policy/); - expectError(/Content Security Policy/); - }); - -
+ it('should throw and report an error when using "eval"', function() { + evilBtn.click(); + expect(evilError.getText()).toMatch(/Content Security Policy/); + expectError(/Content Security Policy/); + }); +
+
*/ // `ngCsp` is not implemented as a proper directive any more, because we need it be processed while @@ -27280,13 +27389,14 @@ var ngControllerDirective = [function() { /** * @ngdoc directive * @name ngClick + * @restrict A + * @element ANY + * @priority 0 * * @description * The ngClick directive allows you to specify custom behavior when * an element is clicked. * - * @element ANY - * @priority 0 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon * click. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27356,12 +27466,13 @@ forEach( /** * @ngdoc directive * @name ngDblclick + * @restrict A + * @element ANY + * @priority 0 * * @description * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event. * - * @element ANY - * @priority 0 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon * a dblclick. (The Event object is available as `$event`) * @@ -27380,12 +27491,13 @@ forEach( /** * @ngdoc directive * @name ngMousedown + * @restrict A + * @element ANY + * @priority 0 * * @description * The ngMousedown directive allows you to specify custom behavior on mousedown event. * - * @element ANY - * @priority 0 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon * mousedown. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27404,12 +27516,13 @@ forEach( /** * @ngdoc directive * @name ngMouseup + * @restrict A + * @element ANY + * @priority 0 * * @description * Specify custom behavior on mouseup event. * - * @element ANY - * @priority 0 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon * mouseup. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27427,12 +27540,13 @@ forEach( /** * @ngdoc directive * @name ngMouseover + * @restrict A + * @element ANY + * @priority 0 * * @description * Specify custom behavior on mouseover event. * - * @element ANY - * @priority 0 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon * mouseover. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27451,12 +27565,13 @@ forEach( /** * @ngdoc directive * @name ngMouseenter + * @restrict A + * @element ANY + * @priority 0 * * @description * Specify custom behavior on mouseenter event. * - * @element ANY - * @priority 0 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27475,12 +27590,13 @@ forEach( /** * @ngdoc directive * @name ngMouseleave + * @restrict A + * @element ANY + * @priority 0 * * @description * Specify custom behavior on mouseleave event. * - * @element ANY - * @priority 0 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27499,12 +27615,13 @@ forEach( /** * @ngdoc directive * @name ngMousemove + * @restrict A + * @element ANY + * @priority 0 * * @description * Specify custom behavior on mousemove event. * - * @element ANY - * @priority 0 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon * mousemove. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27523,12 +27640,13 @@ forEach( /** * @ngdoc directive * @name ngKeydown + * @restrict A + * @element ANY + * @priority 0 * * @description * Specify custom behavior on keydown event. * - * @element ANY - * @priority 0 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.) * @@ -27545,12 +27663,13 @@ forEach( /** * @ngdoc directive * @name ngKeyup + * @restrict A + * @element ANY + * @priority 0 * * @description * Specify custom behavior on keyup event. * - * @element ANY - * @priority 0 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.) * @@ -27572,11 +27691,12 @@ forEach( /** * @ngdoc directive * @name ngKeypress + * @restrict A + * @element ANY * * @description * Specify custom behavior on keypress event. * - * @element ANY * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon * keypress. ({@link guide/expression#-event- Event object is available as `$event`} * and can be interrogated for keyCode, altKey, etc.) @@ -27594,6 +27714,9 @@ forEach( /** * @ngdoc directive * @name ngSubmit + * @restrict A + * @element form + * @priority 0 * * @description * Enables binding angular expressions to onsubmit events. @@ -27609,8 +27732,6 @@ forEach( * for a detailed discussion of when `ngSubmit` may be triggered. * * - * @element form - * @priority 0 * @param {expression} ngSubmit {@link guide/expression Expression} to eval. * ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27657,6 +27778,9 @@ forEach( /** * @ngdoc directive * @name ngFocus + * @restrict A + * @element window, input, select, textarea, a + * @priority 0 * * @description * Specify custom behavior on focus event. @@ -27665,8 +27789,6 @@ forEach( * AngularJS executes the expression using `scope.$evalAsync` if the event is fired * during an `$apply` to ensure a consistent state. * - * @element window, input, select, textarea, a - * @priority 0 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon * focus. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27677,6 +27799,9 @@ forEach( /** * @ngdoc directive * @name ngBlur + * @restrict A + * @element window, input, select, textarea, a + * @priority 0 * * @description * Specify custom behavior on blur event. @@ -27689,8 +27814,6 @@ forEach( * AngularJS executes the expression using `scope.$evalAsync` if the event is fired * during an `$apply` to ensure a consistent state. * - * @element window, input, select, textarea, a - * @priority 0 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon * blur. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27701,12 +27824,13 @@ forEach( /** * @ngdoc directive * @name ngCopy + * @restrict A + * @element window, input, select, textarea, a + * @priority 0 * * @description * Specify custom behavior on copy event. * - * @element window, input, select, textarea, a - * @priority 0 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon * copy. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27722,12 +27846,13 @@ forEach( /** * @ngdoc directive * @name ngCut + * @restrict A + * @element window, input, select, textarea, a + * @priority 0 * * @description * Specify custom behavior on cut event. * - * @element window, input, select, textarea, a - * @priority 0 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon * cut. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27743,12 +27868,13 @@ forEach( /** * @ngdoc directive * @name ngPaste + * @restrict A + * @element window, input, select, textarea, a + * @priority 0 * * @description * Specify custom behavior on paste event. * - * @element window, input, select, textarea, a - * @priority 0 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon * paste. ({@link guide/expression#-event- Event object is available as `$event`}) * @@ -27891,6 +28017,8 @@ var ngIfDirective = ['$animate', '$compile', function($animate, $compile) { * @ngdoc directive * @name ngInclude * @restrict ECA + * @scope + * @priority -400 * * @description * Fetches, compiles and includes an external HTML fragment. @@ -27917,10 +28045,7 @@ var ngIfDirective = ['$animate', '$compile', function($animate, $compile) { * * The enter and leave animation occur concurrently. * - * @scope - * @priority 400 - * - * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant, + * @param {string} ngInclude|src AngularJS expression evaluating to URL. If the source is a string constant, * make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`. * @param {string=} onload Expression to evaluate when a new partial is loaded. *
@@ -28197,6 +28322,10 @@ var ngIncludeFillContentDirective = ['$compile', * @ngdoc directive * @name ngInit * @restrict AC + * @priority 450 + * @element ANY + * + * @param {expression} ngInit {@link guide/expression Expression} to eval. * * @description * The `ngInit` directive allows you to evaluate an expression in the @@ -28204,10 +28333,16 @@ var ngIncludeFillContentDirective = ['$compile', * *
* This directive can be abused to add unnecessary amounts of logic into your templates. - * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of - * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via - * server side scripting. Besides these few cases, you should use {@link guide/controller controllers} - * rather than `ngInit` to initialize values on a scope. + * There are only a few appropriate uses of `ngInit`: + *
    + *
  • aliasing special properties of {@link ng.directive:ngRepeat `ngRepeat`}, + * as seen in the demo below.
  • + *
  • initializing data during development, or for examples, as seen throughout these docs.
  • + *
  • injecting data via server side scripting.
  • + *
+ * + * Besides these few cases, you should use {@link guide/component Components} or + * {@link guide/controller Controllers} rather than `ngInit` to initialize values on a scope. *
* *
@@ -28218,11 +28353,6 @@ var ngIncludeFillContentDirective = ['$compile', * *
* - * @priority 450 - * - * @element ANY - * @param {expression} ngInit {@link guide/expression Expression} to eval. - * * @example @@ -28265,6 +28395,10 @@ var ngInitDirective = ngDirective({ /** * @ngdoc directive * @name ngList + * @restrict A + * @priority 100 + * + * @param {string=} ngList optional delimiter that should be used to split the value. * * @description * Text input that converts between a delimited string and an array of strings. The default @@ -28280,7 +28414,8 @@ var ngInitDirective = ngDirective({ * when joining the list items back together) and whitespace around each list item is stripped * before it is added to the model. * - * ### Example with Validation + * @example + * ### Validation * * * @@ -28327,7 +28462,9 @@ var ngInitDirective = ngDirective({ * * * - * ### Example - splitting on newline + * @example + * ### Splitting on newline + * * * * @@ -28343,8 +28480,6 @@ var ngInitDirective = ngDirective({ * * * - * @element input - * @param {string=} ngList optional delimiter that should be used to split the value. */ var ngListDirective = function() { return { @@ -28415,7 +28550,6 @@ var ngModelMinErr = minErr('ngModel'); /** * @ngdoc type * @name ngModel.NgModelController - * * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue * is set. @@ -28862,6 +28996,7 @@ NgModelController.prototype = { * input which may have such events pending. This is important in order to make sure that the * input field will be updated with the new model value and any pending operations are cancelled. * + * @example * * * angular.module('cancel-update-example', []) @@ -29268,6 +29403,153 @@ NgModelController.prototype = { */ $overrideModelOptions: function(options) { this.$options = this.$options.createChild(options); + }, + + /** + * @ngdoc method + * + * @name ngModel.NgModelController#$processModelValue + + * @description + * + * Runs the model -> view pipeline on the current + * {@link ngModel.NgModelController#$modelValue $modelValue}. + * + * The following actions are performed by this method: + * + * - the `$modelValue` is run through the {@link ngModel.NgModelController#$formatters $formatters} + * and the result is set to the {@link ngModel.NgModelController#$viewValue $viewValue} + * - the `ng-empty` or `ng-not-empty` class is set on the element + * - if the `$viewValue` has changed: + * - {@link ngModel.NgModelController#$render $render} is called on the control + * - the {@link ngModel.NgModelController#$validators $validators} are run and + * the validation status is set. + * + * This method is called by ngModel internally when the bound scope value changes. + * Application developers usually do not have to call this function themselves. + * + * This function can be used when the `$viewValue` or the rendered DOM value are not correctly + * formatted and the `$modelValue` must be run through the `$formatters` again. + * + * @example + * Consider a text input with an autocomplete list (for fruit), where the items are + * objects with a name and an id. + * A user enters `ap` and then selects `Apricot` from the list. + * Based on this, the autocomplete widget will call `$setViewValue({name: 'Apricot', id: 443})`, + * but the rendered value will still be `ap`. + * The widget can then call `ctrl.$processModelValue()` to run the model -> view + * pipeline again, which formats the object to the string `Apricot`, + * then updates the `$viewValue`, and finally renders it in the DOM. + * + * + +
+
+ Search Fruit: + +
+
+ Model:
+
{{selectedFruit | json}}
+
+
+
+ + angular.module('inputExample', []) + .controller('inputController', function($scope) { + $scope.items = [ + {name: 'Apricot', id: 443}, + {name: 'Clementine', id: 972}, + {name: 'Durian', id: 169}, + {name: 'Jackfruit', id: 982}, + {name: 'Strawberry', id: 863} + ]; + }) + .component('basicAutocomplete', { + bindings: { + items: '<', + onSelect: '&' + }, + templateUrl: 'autocomplete.html', + controller: function($element, $scope) { + var that = this; + var ngModel; + + that.$postLink = function() { + ngModel = $element.find('input').controller('ngModel'); + + ngModel.$formatters.push(function(value) { + return (value && value.name) || value; + }); + + ngModel.$parsers.push(function(value) { + var match = value; + for (var i = 0; i < that.items.length; i++) { + if (that.items[i].name === value) { + match = that.items[i]; + break; + } + } + + return match; + }); + }; + + that.selectItem = function(item) { + ngModel.$setViewValue(item); + ngModel.$processModelValue(); + that.onSelect({item: item}); + }; + } + }); + + +
+ +
    +
  • + +
  • +
+
+
+ *
+ * + */ + $processModelValue: function() { + var viewValue = this.$$format(); + + if (this.$viewValue !== viewValue) { + this.$$updateEmptyClasses(viewValue); + this.$viewValue = this.$$lastCommittedViewValue = viewValue; + this.$render(); + // It is possible that model and view value have been updated during render + this.$$runValidators(this.$modelValue, this.$viewValue, noop); + } + }, + + /** + * This method is called internally to run the $formatters on the $modelValue + */ + $$format: function() { + var formatters = this.$formatters, + idx = formatters.length; + + var viewValue = this.$modelValue; + while (idx--) { + viewValue = formatters[idx](viewValue); + } + + return viewValue; + }, + + /** + * This method is called internally when the bound scope value changes. + */ + $$setModelValue: function(modelValue) { + this.$modelValue = this.$$rawModelValue = modelValue; + this.$$parserValid = undefined; + this.$processModelValue(); } }; @@ -29284,30 +29566,14 @@ function setupModelWatcher(ctrl) { var modelValue = ctrl.$$ngModelGet(scope); // if scope model value and ngModel value are out of sync - // TODO(perf): why not move this to the action fn? + // This cannot be moved to the action function, because it would not catch the + // case where the model is changed in the ngChange function or the model setter if (modelValue !== ctrl.$modelValue && - // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator - // eslint-disable-next-line no-self-compare - (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue) + // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator + // eslint-disable-next-line no-self-compare + (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue) ) { - ctrl.$modelValue = ctrl.$$rawModelValue = modelValue; - ctrl.$$parserValid = undefined; - - var formatters = ctrl.$formatters, - idx = formatters.length; - - var viewValue = modelValue; - while (idx--) { - viewValue = formatters[idx](viewValue); - } - if (ctrl.$viewValue !== viewValue) { - ctrl.$$updateEmptyClasses(viewValue); - ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue; - ctrl.$render(); - - // It is possible that model and view value have been updated during render - ctrl.$$runValidators(ctrl.$modelValue, ctrl.$viewValue, noop); - } + ctrl.$$setModelValue(modelValue); } return modelValue; @@ -29350,9 +29616,9 @@ addSetValidityMethod({ /** * @ngdoc directive * @name ngModel - * - * @element input + * @restrict A * @priority 1 + * @param {expression} ngModel assignable {@link guide/expression Expression} to bind to. * * @description * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a @@ -29394,7 +29660,7 @@ addSetValidityMethod({ * - {@link ng.directive:select select} * - {@link ng.directive:textarea textarea} * - * # Complex Models (objects or collections) + * ## Complex Models (objects or collections) * * By default, `ngModel` watches the model by reference, not value. This is important to know when * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the @@ -29410,7 +29676,7 @@ addSetValidityMethod({ * first level of the object (or only changing the properties of an item in the collection if it's an array) will still * not trigger a re-rendering of the model. * - * # CSS classes + * ## CSS classes * The following CSS classes are added and removed on the associated input/select/textarea element * depending on the validity of the model. * @@ -29429,8 +29695,7 @@ addSetValidityMethod({ * * Keep in mind that ngAnimate can detect each of these classes when added and removed. * - * ## Animation Hooks - * + * @animations * Animations within models are triggered when any of the associated CSS classes are added and removed * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`, * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself. @@ -29454,6 +29719,7 @@ addSetValidityMethod({ * * * @example + * ### Basic Usage *