<commit_before>(function (angular) {
'use strict';

	angular.module('ngCaptureWeb', ['ngProgress'])
		// TWEETER SERVICE AUTH AND QUERY
		.service('captureweb', ['$http', function (http) {
			return {
				asyncCaptureWeb: function(data) {
					var queryUrl = '/capturewebquery';
					var promise = http.post(queryUrl, data).then(function (response) {
						return response;
					});
					return promise;
				},

				asyncCaptureWebPdf: function(data) {
					var queryUrl = '/capturewebquerypdf';
					var promise = http.post(queryUrl, data).then(function (response) {
						return response;
					});
					return promise;
				},

				asyncGetUserAgents: function() {
					var queryUrl = '/useragents';
					var promise = http.get(queryUrl).then(function (response) {
						return response;
					});
					return promise;
				}

			};
        }])
		// DIRECTIVE
		.directive('captureweb', ['captureweb', 'ngProgress', '$timeout', '$location', '$anchorScroll',function(captureweb, ngProgress, timeout, location, anchorScroll) {
			return {
				restrict : 'AE',
				scope: { url:'=' },
				template:
					'
' +
                        '

Url	<input type="text" name="input" ng-model="url">
' +
                        '
	{{u.name}}
' +
                        '
Resolution	<select ng-model="resolution" ng-options="r.id for r in resolutions"></select>
' +
                        '
Clip (top,left,width,height)	<input ng-model="rect" type="text" placeholder="10,100,200,300"/>
' +
                        '
	{{c.id}}
' +
                        '
User-Agent	choose
'+
                        	'
{{family.$.description}}
' +
                        		'
{{family2.$.description}}' +
                        			'
' +
		                        		'
{{family3.$.useragent}}' +
		                        		'

' +
	                        		'
' +
		                        		'
{{family3.$.description}}' +
		                        			'
' +
				                        		'
{{family4.$.useragent}}' +
				                        		'

' +
		                        		'

' +
                        		'

' +
                        	'
' +
                        	'
<input ng-model="useragent" type="text" size="83" placeholder="Agent string" />
' +
                        '

' +
					'

' +
                        // '

' +
                        '<button name="capture" ng-click="captureweb()">Capture as IMAGE</button>' +
                        // '

' +
                        '<button name="capture" ng-click="capturewebpdf()">Capture as PDF</button>
' +
                        '
' +
	                        '
' +
	                        // 'Download me' +
	                        '

' +
	                    '
' +
                        // '<button name="helper" ng-click="showDrawHelper()">Position helper</button>' +
                        // '<object id="pdfDoc" data="data:application/pdf;base64,{{jsonpdf.json}}" type="application/pdf" width="100%" height="600px"></object>' +
					'
',
				link : function(scope, element, attrs) {
                    scope.jsonImage = {json: {'info': 'below will your image displayed => click Capture as IMAGE button first'}};
                    scope.jsonPdf = {json: {'info': 'below will your pdf displayed => click Capture as PDF button first'}};
                    scope.resolutions = [
						{id: 'iPhone 3GS (420x480)', name:'420x480'},
						{id: 'Nokia N900 (800x480)', name:'800x480'},
						{id: 'iPhone 4s (960x640)', name:'960x640'},
						{id: 'Galaxy Notes (1280x800)', name:'1280x800'},
						{id: 'iPad 2 (1024x768)', name:'1024x768'},
						{id: 'Galaxy Tab 10,1 (1280x800)', name:'1280x800'},
						{id: 'Playbook (1024x600)', name:'1024x600'},
						{id: 'Galaxy Tab 8,9 (1280x800)', name:'1280x800'},
						{id: 'iPad 3 (2048x1536)', name:'2048x1536'},
						{id: 'Macbook Air (1440x900)', name:'1440x900'},
						{id: 'iMac (2560x1440)', name:'2560x1440'},
						{id: 'Macbook pro Retina (2880x1800)', name:'2880x1800'}
					  ];

					scope.clips = [
						{id: '100,200,200,300', name:'100,200,200,300'},
						{id: '100,200,300,400', name:'100,200,300,400'},
						{id: '100,200,400,500', name:'100,200,400,500'}
					];

					scope.urls = [
						{url: 'http://www.vice.com/', name: 'www.vice.com'},
						{url: 'http://www.nationalgeographic.fr/', name: 'www.nationalgeographic.fr'},
						{url: 'https://maps.google.com/maps/ms?f=q&hl=fr&geocode=&ie=UTF8&msa=0&msid=101908501337757093341.000443bee508411eb6e9a&ll=48.874383,2.372553&spn=0.008581,0.020084&iwloc=00044e3190ebe22c0b86c&source=embed', name: 'gmap example'},
						{url: 'http://rue89.nouvelobs.com/', name: 'rue89.nouvelobs.com'}
					];

					scope.resolution = scope.resolutions[11];

                    var img = document.images[0];
					img.onclick = function() {
					    var url = img.src.replace(/^data:image\/png/, 'data:application/octet-stream');
					    window.location.href = url;
					};

					scope.setAgent = function(agent) { scope.useragent = agent; }
					scope.setClip = function(clip) { scope.rect = clip; }
					scope.setUrl = function(url) { scope.url = url; }

					scope.captureweb = function() {
						var param = {
							url: scope.url,
                     		mime: 'image/png',
                     		viewportSize: { w: scope.resolution.name.split('x')[0], h: scope.resolution.name.split('x')[1] }
                     	};

                     	if (scope.rect)
                     		param.viewportRect = {
                     			top: scope.rect.split(',')[0],
                     			left: scope.rect.split(',')[1],
                     			w: scope.rect.split(',')[2],
                     			h: scope.rect.split(',')[3]
                     		};

                     	if (scope.useragent) param.userAgent = scope.useragent;

                     	ngProgress.start();

						captureweb.asyncCaptureWeb( param ).then(function(d) {
							ngProgress.stop();
							ngProgress.complete();
							scope.jsonpdf = undefined;
							scope.json = {json: 'data:image/png;base64,'+d.data};
							scope.jsonImage = {json: {'info': 'here we are !!!! click on it to download it'}};
							timeout(scope.gotoResult, 1000);
						});
					};

					scope.capturewebpdf = function() {
						var param = {
							url: scope.url,
                     		mime: 'application/pdf',
                     		viewportSize: { w: scope.resolution.name.split('x')[0], h: scope.resolution.name.split('x')[1] }
                     	};

                     	if (scope.rect)
                     		param.viewportRect = {
                     			top: scope.rect.split(',')[0],
                     			left: scope.rect.split(',')[1],
                     			w: scope.rect.split(',')[2],
                     			h: scope.rect.split(',')[3]
                     		};

                     	if (scope.useragent) param.userAgent = scope.useragent;

                     	ngProgress.start();

						captureweb.asyncCaptureWebPdf( param ).then(function(d) {
							ngProgress.stop();
							ngProgress.complete();
							scope.json = undefined;
							scope.jsonpdf = {json: d.data};
							$('#pdfDoc').html('<object id="pdfDoc" data="data:application/pdf;base64,'+scope.jsonpdf.json+'" type="application/pdf" width="100%" height="600px"></object>');
							scope.jsonImage = {json: {'info': 'here we are !!!! you can save it '}};
							timeout(scope.gotoResult, 1000);
						});
					};

					scope.fetchUserAgents = function() {
						captureweb.asyncGetUserAgents( ).then(function(d) {
							if (d && d.data && d.data.useragentswitcher)
							scope.useragents = d.data.useragentswitcher.folder;
							scope.useragents = scope.useragents.slice(0, 5);
							// clean
							scope.useragents[2].folder = scope.useragents[3].folder.slice(1,2);
							scope.useragents[3].folder = scope.useragents[3].folder.slice(1,2);
							scope.useragents[4].folder = scope.useragents[4].folder.slice(0,3);
						});
					};

					scope.fetchUserAgents();

					scope.showDrawHelper = function() {
						showCanvas();
					};

					scope.generateIds = function(id) {
						var re = new RegExp('[ ()]', 'g');
						return id.replace(re, '_');
					};

					scope.toggleAgents = function(id) { $('#'+id).toggle(); };
					scope.toggleAgentPanel = function(id) { $('#agentPanel').toggle();};

					scope.gotoResult = function (){
					    // set the location.hash to the id of
					    // the element you wish to scroll to.
					    location.hash('result');

					    // call $anchorScroll()
					    anchorScroll();
					 };

				}
			};
		}]);
})(angular);<commit_msg>lower res<commit_after>(function (angular) {
'use strict';

	angular.module('ngCaptureWeb', ['ngProgress'])
		// TWEETER SERVICE AUTH AND QUERY
		.service('captureweb', ['$http', function (http) {
			return {
				asyncCaptureWeb: function(data) {
					var queryUrl = '/capturewebquery';
					var promise = http.post(queryUrl, data).then(function (response) {
						return response;
					});
					return promise;
				},

				asyncCaptureWebPdf: function(data) {
					var queryUrl = '/capturewebquerypdf';
					var promise = http.post(queryUrl, data).then(function (response) {
						return response;
					});
					return promise;
				},

				asyncGetUserAgents: function() {
					var queryUrl = '/useragents';
					var promise = http.get(queryUrl).then(function (response) {
						return response;
					});
					return promise;
				}

			};
        }])
		// DIRECTIVE
		.directive('captureweb', ['captureweb', 'ngProgress', '$timeout', '$location', '$anchorScroll',function(captureweb, ngProgress, timeout, location, anchorScroll) {
			return {
				restrict : 'AE',
				scope: { url:'=' },
				template:
					'
' +
                        '

Url	<input type="text" name="input" ng-model="url">
' +
                        '
	{{u.name}}
' +
                        '
Resolution	<select ng-model="resolution" ng-options="r.id for r in resolutions"></select>
' +
                        '
Clip (top,left,width,height)	<input ng-model="rect" type="text" placeholder="10,100,200,300"/>
' +
                        '
	{{c.id}}
' +
                        '
User-Agent	choose
'+
                        	'
{{family.$.description}}
' +
                        		'
{{family2.$.description}}' +
                        			'
' +
		                        		'
{{family3.$.useragent}}' +
		                        		'

' +
	                        		'
' +
		                        		'
{{family3.$.description}}' +
		                        			'
' +
				                        		'
{{family4.$.useragent}}' +
				                        		'

' +
		                        		'

' +
                        		'

' +
                        	'
' +
                        	'
<input ng-model="useragent" type="text" size="83" placeholder="Agent string" />
' +
                        '

' +
					'

' +
                        // '

' +
                        '<button name="capture" ng-click="captureweb()">Capture as IMAGE</button>' +
                        // '

' +
                        '<button name="capture" ng-click="capturewebpdf()">Capture as PDF</button>
' +
                        '
' +
	                        '
' +
	                        // 'Download me' +
	                        '

' +
	                    '
' +
                        // '<button name="helper" ng-click="showDrawHelper()">Position helper</button>' +
                        // '<object id="pdfDoc" data="data:application/pdf;base64,{{jsonpdf.json}}" type="application/pdf" width="100%" height="600px"></object>' +
					'
',
				link : function(scope, element, attrs) {
                    scope.jsonImage = {json: {'info': 'below will your image displayed => click Capture as IMAGE button first'}};
                    scope.jsonPdf = {json: {'info': 'below will your pdf displayed => click Capture as PDF button first'}};
                    scope.resolutions = [
						{id: 'iPhone 3GS (420x480)', name:'420x480'},
						{id: 'Nokia N900 (800x480)', name:'800x480'},
						{id: 'iPhone 4s (960x640)', name:'960x640'},
						{id: 'Galaxy Notes (1280x800)', name:'1280x800'},
						{id: 'iPad 2 (1024x768)', name:'1024x768'},
						{id: 'Galaxy Tab 10,1 (1280x800)', name:'1280x800'},
						{id: 'Playbook (1024x600)', name:'1024x600'},
						{id: 'Galaxy Tab 8,9 (1280x800)', name:'1280x800'},
						{id: 'iPad 3 (2048x1536)', name:'2048x1536'},
						{id: 'Macbook Air (1440x900)', name:'1440x900'},
						{id: 'iMac (2560x1440)', name:'2560x1440'},
						{id: 'Macbook pro Retina (2880x1800)', name:'2880x1800'}
					  ];

					scope.clips = [
						{id: '100,200,200,300', name:'100,200,200,300'},
						{id: '100,200,300,400', name:'100,200,300,400'},
						{id: '100,200,400,500', name:'100,200,400,500'}
					];

					scope.urls = [
						{url: 'http://www.vice.com/', name: 'www.vice.com'},
						{url: 'http://www.nationalgeographic.fr/', name: 'www.nationalgeographic.fr'},
						{url: 'https://maps.google.com/maps/ms?f=q&hl=fr&geocode=&ie=UTF8&msa=0&msid=101908501337757093341.000443bee508411eb6e9a&ll=48.874383,2.372553&spn=0.008581,0.020084&iwloc=00044e3190ebe22c0b86c&source=embed', name: 'gmap example'},
						{url: 'http://rue89.nouvelobs.com/', name: 'rue89.nouvelobs.com'}
					];

					scope.resolution = scope.resolutions[4];

                    var img = document.images[0];
					img.onclick = function() {
					    var url = img.src.replace(/^data:image\/png/, 'data:application/octet-stream');
					    window.location.href = url;
					};

					scope.setAgent = function(agent) { scope.useragent = agent; }
					scope.setClip = function(clip) { scope.rect = clip; }
					scope.setUrl = function(url) { scope.url = url; }

					scope.captureweb = function() {
						var param = {
							url: scope.url,
                     		mime: 'image/png',
                     		viewportSize: { w: scope.resolution.name.split('x')[0], h: scope.resolution.name.split('x')[1] }
                     	};

                     	if (scope.rect)
                     		param.viewportRect = {
                     			top: scope.rect.split(',')[0],
                     			left: scope.rect.split(',')[1],
                     			w: scope.rect.split(',')[2],
                     			h: scope.rect.split(',')[3]
                     		};

                     	if (scope.useragent) param.userAgent = scope.useragent;

                     	ngProgress.start();

						captureweb.asyncCaptureWeb( param ).then(function(d) {
							ngProgress.stop();
							ngProgress.complete();
							scope.jsonpdf = undefined;
							scope.json = {json: 'data:image/png;base64,'+d.data};
							scope.jsonImage = {json: {'info': 'here we are !!!! click on it to download it'}};
							timeout(scope.gotoResult, 1000);
						});
					};

					scope.capturewebpdf = function() {
						var param = {
							url: scope.url,
                     		mime: 'application/pdf',
                     		viewportSize: { w: scope.resolution.name.split('x')[0], h: scope.resolution.name.split('x')[1] }
                     	};

                     	if (scope.rect)
                     		param.viewportRect = {
                     			top: scope.rect.split(',')[0],
                     			left: scope.rect.split(',')[1],
                     			w: scope.rect.split(',')[2],
                     			h: scope.rect.split(',')[3]
                     		};

                     	if (scope.useragent) param.userAgent = scope.useragent;

                     	ngProgress.start();

						captureweb.asyncCaptureWebPdf( param ).then(function(d) {
							ngProgress.stop();
							ngProgress.complete();
							scope.json = undefined;
							scope.jsonpdf = {json: d.data};
							$('#pdfDoc').html('<object id="pdfDoc" data="data:application/pdf;base64,'+scope.jsonpdf.json+'" type="application/pdf" width="100%" height="600px"></object>');
							scope.jsonImage = {json: {'info': 'here we are !!!! you can save it '}};
							timeout(scope.gotoResult, 1000);
						});
					};

					scope.fetchUserAgents = function() {
						captureweb.asyncGetUserAgents( ).then(function(d) {
							if (d && d.data && d.data.useragentswitcher)
							scope.useragents = d.data.useragentswitcher.folder;
							scope.useragents = scope.useragents.slice(0, 5);
							// clean
							scope.useragents[2].folder = scope.useragents[3].folder.slice(1,2);
							scope.useragents[3].folder = scope.useragents[3].folder.slice(1,2);
							scope.useragents[4].folder = scope.useragents[4].folder.slice(0,3);
						});
					};

					scope.fetchUserAgents();

					scope.showDrawHelper = function() {
						showCanvas();
					};

					scope.generateIds = function(id) {
						var re = new RegExp('[ ()]', 'g');
						return id.replace(re, '_');
					};

					scope.toggleAgents = function(id) { $('#'+id).toggle(); };
					scope.toggleAgentPanel = function(id) { $('#agentPanel').toggle();};

					scope.gotoResult = function (){
					    // set the location.hash to the id of
					    // the element you wish to scroll to.
					    location.hash('result');

					    // call $anchorScroll()
					    anchorScroll();
					 };

				}
			};
		}]);
})(angular);<|endoftext|>


<commit_before>/*
Copyright 2020 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import { MatrixClientPeg } from './MatrixClientPeg';
import SettingsStore from './settings/SettingsStore';
import * as sdk from './index';
import { _t } from './languageHandler';
import ToastStore from './stores/ToastStore';

function toastKey(device) {
    return 'newsession_' + device.deviceId;
}

const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000;
const THIS_DEVICE_TOAST_KEY = 'setupencryption';

export default class DeviceListener {
    static sharedInstance() {
        if (!global.mx_DeviceListener) global.mx_DeviceListener = new DeviceListener();
        return global.mx_DeviceListener;
    }

    constructor() {
        // device IDs for which the user has dismissed the verify toast ('Later')
        this._dismissed = new Set();
        // has the user dismissed any of the various nag toasts to setup encryption on this device?
        this._dismissedThisDeviceToast = false;

        // cache of the key backup info
        this._keyBackupInfo = null;
        this._keyBackupFetchedAt = null;
    }

    start() {
        MatrixClientPeg.get().on('crypto.devicesUpdated', this._onDevicesUpdated);
        MatrixClientPeg.get().on('deviceVerificationChanged', this._onDeviceVerificationChanged);
        MatrixClientPeg.get().on('userTrustStatusChanged', this._onUserTrustStatusChanged);
        this._recheck();
    }

    stop() {
        if (MatrixClientPeg.get()) {
            MatrixClientPeg.get().removeListener('crypto.devicesUpdated', this._onDevicesUpdated);
            MatrixClientPeg.get().removeListener('deviceVerificationChanged', this._onDeviceVerificationChanged);
            MatrixClientPeg.get().removeListener('userTrustStatusChanged', this._onUserTrustStatusChanged);
        }
        this._dismissed.clear();
    }

    dismissVerification(deviceId) {
        this._dismissed.add(deviceId);
        this._recheck();
    }

    dismissEncryptionSetup() {
        this._dismissedThisDeviceToast = true;
        this._recheck();
    }

    _onDevicesUpdated = (users) => {
        if (!users.includes(MatrixClientPeg.get().getUserId())) return;
        this._recheck();
    }

    _onDeviceVerificationChanged = (users) => {
        if (!users.includes(MatrixClientPeg.get().getUserId())) return;
        this._recheck();
    }

    _onUserTrustStatusChanged = (userId, trustLevel) => {
        if (userId !== MatrixClientPeg.get().getUserId()) return;
        this._recheck();
    }

    // The server doesn't tell us when key backup is set up, so we poll
    // & cache the result
    async _getKeyBackupInfo() {
        const now = (new Date()).getTime();
        if (!this._keyBackupInfo || this._keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) {
            this._keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
            this._keyBackupFetchedAt = now;
        }
        return this._keyBackupInfo;
    }

    async _recheck() {
        if (!SettingsStore.isFeatureEnabled("feature_cross_signing")) return;
        const cli = MatrixClientPeg.get();

        if (!cli.isCryptoEnabled()) return;
        if (!cli.getCrossSigningId()) {
            if (this._dismissedThisDeviceToast) {
                ToastStore.sharedInstance().dismissToast(THIS_DEVICE_TOAST_KEY);
                return;
            }

            // cross signing isn't enabled - nag to enable it
            // There are 3 different toasts for:
            if (cli.getStoredCrossSigningForUser(cli.getUserId())) {
                // Cross-signing on account but this device doesn't trust the master key (verify this session)
                ToastStore.sharedInstance().addOrReplaceToast({
                    key: THIS_DEVICE_TOAST_KEY,
                    title: _t("Verify this Session"),
                    icon: "verification_warning",
                    props: {kind: 'verify_this_session'},
                    component: sdk.getComponent("toasts.SetupEncryptionToast"),
                });
            } else {
                const backupInfo = await this._getKeyBackupInfo();
                if (backupInfo) {
                    // No cross-signing on account but key backup available (upgrade encryption)
                    ToastStore.sharedInstance().addOrReplaceToast({
                        key: THIS_DEVICE_TOAST_KEY,
                        title: _t("Encryption upgrade available"),
                        icon: "verification_warning",
                        props: {kind: 'upgrade_encryption'},
                        component: sdk.getComponent("toasts.SetupEncryptionToast"),
                    });
                } else {
                    // No cross-signing or key backup on account (set up encryption)
                    ToastStore.sharedInstance().addOrReplaceToast({
                        key: THIS_DEVICE_TOAST_KEY,
                        title: _t("Set up encryption"),
                        icon: "verification_warning",
                        props: {kind: 'set_up_encryption'},
                        component: sdk.getComponent("toasts.SetupEncryptionToast"),
                    });
                }
            }
            return;
        } else {
            ToastStore.sharedInstance().dismissToast(THIS_DEVICE_TOAST_KEY);
        }

        const devices = await cli.getStoredDevicesForUser(cli.getUserId());
        for (const device of devices) {
            if (device.deviceId == cli.deviceId) continue;

            const deviceTrust = await cli.checkDeviceTrust(cli.getUserId(), device.deviceId);
            if (deviceTrust.isCrossSigningVerified() || this._dismissed.has(device.deviceId)) {
                ToastStore.sharedInstance().dismissToast(toastKey(device));
            } else {
                ToastStore.sharedInstance().addOrReplaceToast({
                    key: toastKey(device),
                    title: _t("New Session"),
                    icon: "verification_warning",
                    props: {deviceId: device.deviceId},
                    component: sdk.getComponent("toasts.NewSessionToast"),
                });
            }
        }
    }
}
<commit_msg>Capitalisation<commit_after>/*
Copyright 2020 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import { MatrixClientPeg } from './MatrixClientPeg';
import SettingsStore from './settings/SettingsStore';
import * as sdk from './index';
import { _t } from './languageHandler';
import ToastStore from './stores/ToastStore';

function toastKey(device) {
    return 'newsession_' + device.deviceId;
}

const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000;
const THIS_DEVICE_TOAST_KEY = 'setupencryption';

export default class DeviceListener {
    static sharedInstance() {
        if (!global.mx_DeviceListener) global.mx_DeviceListener = new DeviceListener();
        return global.mx_DeviceListener;
    }

    constructor() {
        // device IDs for which the user has dismissed the verify toast ('Later')
        this._dismissed = new Set();
        // has the user dismissed any of the various nag toasts to setup encryption on this device?
        this._dismissedThisDeviceToast = false;

        // cache of the key backup info
        this._keyBackupInfo = null;
        this._keyBackupFetchedAt = null;
    }

    start() {
        MatrixClientPeg.get().on('crypto.devicesUpdated', this._onDevicesUpdated);
        MatrixClientPeg.get().on('deviceVerificationChanged', this._onDeviceVerificationChanged);
        MatrixClientPeg.get().on('userTrustStatusChanged', this._onUserTrustStatusChanged);
        this._recheck();
    }

    stop() {
        if (MatrixClientPeg.get()) {
            MatrixClientPeg.get().removeListener('crypto.devicesUpdated', this._onDevicesUpdated);
            MatrixClientPeg.get().removeListener('deviceVerificationChanged', this._onDeviceVerificationChanged);
            MatrixClientPeg.get().removeListener('userTrustStatusChanged', this._onUserTrustStatusChanged);
        }
        this._dismissed.clear();
    }

    dismissVerification(deviceId) {
        this._dismissed.add(deviceId);
        this._recheck();
    }

    dismissEncryptionSetup() {
        this._dismissedThisDeviceToast = true;
        this._recheck();
    }

    _onDevicesUpdated = (users) => {
        if (!users.includes(MatrixClientPeg.get().getUserId())) return;
        this._recheck();
    }

    _onDeviceVerificationChanged = (users) => {
        if (!users.includes(MatrixClientPeg.get().getUserId())) return;
        this._recheck();
    }

    _onUserTrustStatusChanged = (userId, trustLevel) => {
        if (userId !== MatrixClientPeg.get().getUserId()) return;
        this._recheck();
    }

    // The server doesn't tell us when key backup is set up, so we poll
    // & cache the result
    async _getKeyBackupInfo() {
        const now = (new Date()).getTime();
        if (!this._keyBackupInfo || this._keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) {
            this._keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
            this._keyBackupFetchedAt = now;
        }
        return this._keyBackupInfo;
    }

    async _recheck() {
        if (!SettingsStore.isFeatureEnabled("feature_cross_signing")) return;
        const cli = MatrixClientPeg.get();

        if (!cli.isCryptoEnabled()) return;
        if (!cli.getCrossSigningId()) {
            if (this._dismissedThisDeviceToast) {
                ToastStore.sharedInstance().dismissToast(THIS_DEVICE_TOAST_KEY);
                return;
            }

            // cross signing isn't enabled - nag to enable it
            // There are 3 different toasts for:
            if (cli.getStoredCrossSigningForUser(cli.getUserId())) {
                // Cross-signing on account but this device doesn't trust the master key (verify this session)
                ToastStore.sharedInstance().addOrReplaceToast({
                    key: THIS_DEVICE_TOAST_KEY,
                    title: _t("Verify this session"),
                    icon: "verification_warning",
                    props: {kind: 'verify_this_session'},
                    component: sdk.getComponent("toasts.SetupEncryptionToast"),
                });
            } else {
                const backupInfo = await this._getKeyBackupInfo();
                if (backupInfo) {
                    // No cross-signing on account but key backup available (upgrade encryption)
                    ToastStore.sharedInstance().addOrReplaceToast({
                        key: THIS_DEVICE_TOAST_KEY,
                        title: _t("Encryption upgrade available"),
                        icon: "verification_warning",
                        props: {kind: 'upgrade_encryption'},
                        component: sdk.getComponent("toasts.SetupEncryptionToast"),
                    });
                } else {
                    // No cross-signing or key backup on account (set up encryption)
                    ToastStore.sharedInstance().addOrReplaceToast({
                        key: THIS_DEVICE_TOAST_KEY,
                        title: _t("Set up encryption"),
                        icon: "verification_warning",
                        props: {kind: 'set_up_encryption'},
                        component: sdk.getComponent("toasts.SetupEncryptionToast"),
                    });
                }
            }
            return;
        } else {
            ToastStore.sharedInstance().dismissToast(THIS_DEVICE_TOAST_KEY);
        }

        const devices = await cli.getStoredDevicesForUser(cli.getUserId());
        for (const device of devices) {
            if (device.deviceId == cli.deviceId) continue;

            const deviceTrust = await cli.checkDeviceTrust(cli.getUserId(), device.deviceId);
            if (deviceTrust.isCrossSigningVerified() || this._dismissed.has(device.deviceId)) {
                ToastStore.sharedInstance().dismissToast(toastKey(device));
            } else {
                ToastStore.sharedInstance().addOrReplaceToast({
                    key: toastKey(device),
                    title: _t("New Session"),
                    icon: "verification_warning",
                    props: {deviceId: device.deviceId},
                    component: sdk.getComponent("toasts.NewSessionToast"),
                });
            }
        }
    }
}
<|endoftext|>


<commit_before>/**
 * jQuery.spModal - A Modal Window System.
 *
 * This plugin requires:
 *      1. jQuery >= 2.1.3
 *      2. jQuery.ui >= 1.11.4
 *
 * @author    Gonzalo Chumillas <gchumillas@email.com>
 * @license   https://github.com/soloproyectos/jquery.modal/blob/master/LICENSE MIT License
 * @link      https://github.com/soloproyectos/jquery.modal
 */
(function ($) {
    var methods = {
        /**
         * Creates a modal window.
         *
         * A modal window is an iFrame covering all the available window. See the example included in
         * /demos/modal-window for more info.
         *
         * Example:
         * ```JavaScript
         * var mw = $.spModal('window', 'user-interface.html', {param1: 'one', param2: 'two'});
         * mw.on('event', function () {
         *      // Performs some actions and close the modal window
         *      mw.close();
         * });
         * ```
         *
         * @param {String} url    URL to the user interface
         * @param {Object} params Parameters (not required)
         *
         * @return {$.spModalWindow}
         */
        'window': function (url, params) {
            return new $.spModalWindow(url, params);
        },

        /**
         * User Interface class.
         *
         * See the example included in /demos/modal-window for more info.
         *
         * Example:
         * ```JavaScript
         * var target = $('#my-user-interface');
         * var ui = $.spModal('ui', target);
         *
         * // populates data
         * $('#title').text(ui.getParam('title'));
         * $('#message').text(ui.getParam('message'));
         *
         * $('#button1').on('click', function () {
         *      // tells the parent window to perform the action-1
         *      // the event will be captured by the parent window
         *      ui.trigger('action-1');
         * });
         * ```
         *
         * @param {jQuery.<HTMLElement>} target      User Interface
         * @param {jQuery.<HTMLElement>} modalWindow Modal window container (not required)
         *
         * @return {$.spModalUi}
         */
        'ui': function (target, modalWindow) {
            return new $.spModalUi(target, modalWindow);
        },

        /**
         * Modal message dialog.
         *
         * See the example included in /demos/modal-message for more info.
         *
         * Example:
         * ```JavaScript
         * var msg = $.spModal('message', 'My Title', 'This is a message...');
         * msg.setX(100);
         * msg.setY(50);
         * ```
         *
         * @param {String} title   Title
         * @param {String} message Message (not required)
         *
         * @return {$.spModalMessage}
         */
        'message': function (title, message) {
            return new $.spModalMessage(title, message);
        },

        /**
         * Shows a modal alert dialog.
         *
         * An alert dialog is a modal message dialog with a button. If the 'message' parameter
         * is missing, the 'title' is taken as message and a default title is used.
         *
         * Examples:
         * ```JavaScript:
         * // shows an alert dialog with a title and a message
         * $.spModal('alert', 'Alert', 'Hi there!');
         *
         * // shows an alert dialog witha a default title and a message
         * $.spModal('alert', 'Hi there!');
         * ```
         *
         * @param {String} title   Title or message
         * @param {Strimg} message Message
         *
         * @return {$.spModalMessage}
         */
        'alert': function (title, message) {
            // title is missing
            if (arguments.length < 2) {
                message = title;
                title = 'Alert';
            }

            var msg = new $.spModalMessage(title, message);
            msg.addButton('Ok', function () {
                msg.close();
            });

            return msg;
        },

        /**
         * Shows a modal confirm dialog.
         *
         * A confirm dialog is a modal message dialog with two buttons: 'Ok' and 'Cancel'.
         * This function can take 2 or 3 arguments. When taking 2 arguments, the function assumes that
         * the title is missing and it uses a default title.
         *
         * Example:
         * ```JavaScript
         * $.spModal('confirm', 'Are you sure?', function () {
         *     console.log('Oh yes!');
         * });
         * ```
         *
         * @param {String}   title    Title of message
         * @param {String}   message  Message
         * @param {Fucntion} onAccept 'On accept' function
         *
         * @return {$.spModalMessage}
         */
        'confirm': function (title, message, onAccept) {
            // title is missing
            if (arguments.length < 3) {
                onAccept = message;
                message = title;
                title = 'Confirm';
            }

            var msg = new $.spModalMessage(title, message);
            msg.addButton('Ok', function () {
                msg.close();
                $.proxy(onAccept, this)();
            });
            msg.addButton('Cancel', function () {
                msg.close();
            });

            return msg;
        },

        /**
         * Shows an modal error dialog and throws an error.
         *
         * An error dialog is a modal message dialog with a button. If the 'message' parameter
         * is missing, the 'title' is taken as message and a default title is used.
         *
         * Example:
         * ```JavaScript
         * // shows and throws an error with a default title
         * $.spModal('error', 'Oh my God!');
         *
         * // shows and throws an error with a custom title
         * $.spModal('error', 'Error!', 'Oh my God!');
         * ```
         *
         * @param {String}   title   Title of message
         * @param {String}   message Message
         * @param {Function} onReady Called when the message dialog is ready
         *
         * @return {Void}
         */
        'error': function (title, message, onReady) {
            // title is missing
            if ($.type(title) != 'string' || $.type(message) != 'string') {
                onReady = message;
                message = title;
                title = 'Error';
            }

            // makes the modal dialog
            var msg = new $.spModalMessage(title, message);
            msg.addButton('Ok', function () {
                msg.close();
            });

            // calls the initialization function
            if (onReady !== undefined) {
                $.proxy(onReady, msg)();
            }

            $.error(message);
        },

        /**
         * Modal loading dialog.
         *
         * See the example included in /demos/modal-loading for more info.
         *
         * Example:
         * ```JavaScript
         * var loading = $.spModal('loading', 'This process may take several minutes...');
         * loading.addButton('Cancel', function () {
         *      // canceling process...
         *      loading.close();
         * });
         * ```
         *
         * @param {String} message Message (not required)
         *
         * @return {$.spModalLoading}
         */
        'loading': function (message) {
            return new $.spModalLoading(message);
        },

        /**
         * Sends a GET request.
         *
         * This function uses internally the $.get function and accepts the same parameters. More info:
         * https://api.jquery.com/jquery.get/
         *
         * Example:
         * ```JavaScript
         * $.spModal('get', 'test.php', {one: 1, two: 2, three: 3}).always(function () {
         *     console.log('This is always executed');
         * }).done(function (data) {
         *     console.log('This is executed on success requests');
         * }).fail(function () {
         *     console.log('This is executed on failed requests');
         * });
         * ```
         *
         * @param {Mixed} args Additional arguments
         *
         * @return {jQuery.Promise}
         */
        'get': function (args) {
            // Based on a Matthew Crumley solution,
            // as we can't use the .apply() method in conjunction with the 'new' operator
            // http://goo.gl/PRL0eZ (redirects to http://stackoverflow.com)
            function F(args) {
                return $.spModalRequestGet.apply(this, args);
            }
            F.prototype = $.spModalRequestGet.prototype;

            var req = new F(arguments);
            return req.send();
        },

        /**
         * Sends a POST request.
         *
         * This function uses internally the $.get function and accepts the same parameters. More info:
         * https://api.jquery.com/jquery.post/
         *
         * Example:
         * ```JavaScript
         * $.spModal('post', 'test.php', {one: 1, two: 2, three: 3}).always(function () {
         *     console.log('This is always executed');
         * }).done(function (data) {
         *     console.log('This is executed on success requests');
         * }).fail(function () {
         *     console.log('This is executed on failed requests');
         * });
         * ```
         *
         * @param {Mixed} args Additional arguments
         *
         * @return {jQuery.Promise}
         */
        'post': function (args) {
            // Based on a Matthew Crumley solution,
            // as we can't use the .apply() method in conjunction with the 'new' operator
            // http://goo.gl/PRL0eZ (redirects to http://stackoverflow.com)
            function F(args) {
                return $.spModalRequestPost.apply(this, args);
            }
            F.prototype = $.spModalRequestPost.prototype;

            var req = new F(arguments);
            return req.send();
        },

        /**
         * Sends a POST request and uploads files.
         *
         * Example:
         * ```JavaScript
         * var inputFile = $('#file');
         * inputFile.change(function () {
         *     $.spModal('upload', inputFile, 'test.php', {one: 1, two: 2}).done(function (data) {
         *         console.log(data);
         *     }).fail(function () {
         *         console.log('failed!');
         *     });
         * });
         * ```
         *
         * @param {jQuery.<HTMLInputElement>|String} input Input file(s)
         * @param {String}                           url   URL
         * @param {Object}                           data  Parameters (not required)
         *
         * @return {jQuery.Promise}
         */
        'upload': function (input, url, data) {
            var req = new $.spModalRequestUpload(input, url, data);
            return req.send();
        }
    };

    /**
     * Registers plugin.
     *
     * @param {String} methodName Method name
     * @param {Mixed}  args,...   Additional arguments (not required)
     *
     * @return {Mixed}
     */
    $.spModal = function (methodName, args) {
        var method = methods[methodName];
        var args = Array.prototype.slice.call(arguments, 1);

        if (method === undefined) {
            $.error('Method not found: ' + methodName);
        }

        return method.apply(this, args);
    };
})(jQuery);
<commit_msg>doc: add example<commit_after>/**
 * jQuery.spModal - A Modal Window System.
 *
 * This plugin requires:
 *      1. jQuery >= 2.1.3
 *      2. jQuery.ui >= 1.11.4
 *
 * @author    Gonzalo Chumillas <gchumillas@email.com>
 * @license   https://github.com/soloproyectos/jquery.modal/blob/master/LICENSE MIT License
 * @link      https://github.com/soloproyectos/jquery.modal
 */
(function ($) {
    var methods = {
        /**
         * Creates a modal window.
         *
         * A modal window is an iFrame covering all the available window. See the example included in
         * /demos/modal-window for more info.
         *
         * Example:
         * ```JavaScript
         * var mw = $.spModal('window', 'user-interface.html', {param1: 'one', param2: 'two'});
         * mw.on('event', function () {
         *      // Performs some actions and close the modal window
         *      mw.close();
         * });
         * ```
         *
         * @param {String} url    URL to the user interface
         * @param {Object} params Parameters (not required)
         *
         * @return {$.spModalWindow}
         */
        'window': function (url, params) {
            return new $.spModalWindow(url, params);
        },

        /**
         * User Interface class.
         *
         * See the example included in /demos/modal-window for more info.
         *
         * Example:
         * ```JavaScript
         * var target = $('#my-user-interface');
         * var ui = $.spModal('ui', target);
         *
         * // populates data
         * $('#title').text(ui.getParam('title'));
         * $('#message').text(ui.getParam('message'));
         *
         * $('#button1').on('click', function () {
         *      // tells the parent window to perform the action-1
         *      // the event will be captured by the parent window
         *      ui.trigger('action-1');
         * });
         * ```
         *
         * @param {jQuery.<HTMLElement>} target      User Interface
         * @param {jQuery.<HTMLElement>} modalWindow Modal window container (not required)
         *
         * @return {$.spModalUi}
         */
        'ui': function (target, modalWindow) {
            return new $.spModalUi(target, modalWindow);
        },

        /**
         * Modal message dialog.
         *
         * See the example included in /demos/modal-message for more info.
         *
         * Example:
         * ```JavaScript
         * var msg = $.spModal('message', 'My Title', 'This is a message...');
         * msg.setX(100);
         * msg.setY(50);
         * ```
         *
         * @param {String} title   Title
         * @param {String} message Message (not required)
         *
         * @return {$.spModalMessage}
         */
        'message': function (title, message) {
            return new $.spModalMessage(title, message);
        },

        /**
         * Shows a modal alert dialog.
         *
         * An alert dialog is a modal message dialog with a button. If the 'message' parameter
         * is missing, the 'title' is taken as message and a default title is used.
         *
         * Examples:
         * ```JavaScript:
         * // shows an alert dialog with a title and a message
         * $.spModal('alert', 'Alert', 'Hi there!');
         *
         * // shows an alert dialog witha a default title and a message
         * $.spModal('alert', 'Hi there!');
         * ```
         *
         * @param {String} title   Title or message
         * @param {Strimg} message Message
         *
         * @return {$.spModalMessage}
         */
        'alert': function (title, message) {
            // title is missing
            if (arguments.length < 2) {
                message = title;
                title = 'Alert';
            }

            var msg = new $.spModalMessage(title, message);
            msg.addButton('Ok', function () {
                msg.close();
            });

            return msg;
        },

        /**
         * Shows a modal confirm dialog.
         *
         * A confirm dialog is a modal message dialog with two buttons: 'Ok' and 'Cancel'.
         * This function can take 2 or 3 arguments. When taking 2 arguments, the function assumes that
         * the title is missing and it uses a default title.
         *
         * Example:
         * ```JavaScript
         * $.spModal('confirm', 'Are you sure?', function () {
         *     console.log('Oh yes!');
         * });
         * ```
         *
         * @param {String}   title    Title of message
         * @param {String}   message  Message
         * @param {Fucntion} onAccept 'On accept' function
         *
         * @return {$.spModalMessage}
         */
        'confirm': function (title, message, onAccept) {
            // title is missing
            if (arguments.length < 3) {
                onAccept = message;
                message = title;
                title = 'Confirm';
            }

            var msg = new $.spModalMessage(title, message);
            msg.addButton('Ok', function () {
                msg.close();
                $.proxy(onAccept, this)();
            });
            msg.addButton('Cancel', function () {
                msg.close();
            });

            return msg;
        },

        /**
         * Shows an modal error dialog and throws an error.
         *
         * An error dialog is a modal message dialog with a button. If the 'message' parameter
         * is missing, the 'title' is taken as message and a default title is used.
         *
         * Example:
         * ```JavaScript
         * // shows and throws an error with a default title
         * $.spModal('error', 'Oh my God!');
         *
         * // shows and throws an error with a custom title
         * $.spModal('error', 'Error!', 'Oh my God!');
         *
         * // initializes the error dialog, shows a message and throws an error
         * $.spModal('error', 'This is an error', function () {
         *     this.setTextAlign('left');
         *     this.setHtml(true);
         * });
         * ```
         *
         * @param {String}   title   Title of message
         * @param {String}   message Message
         * @param {Function} onReady Called when the message dialog is ready
         *
         * @return {Void}
         */
        'error': function (title, message, onReady) {
            // title is missing
            if ($.type(title) != 'string' || $.type(message) != 'string') {
                onReady = message;
                message = title;
                title = 'Error';
            }

            // makes the modal dialog
            var msg = new $.spModalMessage(title, message);
            msg.addButton('Ok', function () {
                msg.close();
            });

            // calls the initialization function
            if (onReady !== undefined) {
                $.proxy(onReady, msg)();
            }

            $.error(message);
        },

        /**
         * Modal loading dialog.
         *
         * See the example included in /demos/modal-loading for more info.
         *
         * Example:
         * ```JavaScript
         * var loading = $.spModal('loading', 'This process may take several minutes...');
         * loading.addButton('Cancel', function () {
         *      // canceling process...
         *      loading.close();
         * });
         * ```
         *
         * @param {String} message Message (not required)
         *
         * @return {$.spModalLoading}
         */
        'loading': function (message) {
            return new $.spModalLoading(message);
        },

        /**
         * Sends a GET request.
         *
         * This function uses internally the $.get function and accepts the same parameters. More info:
         * https://api.jquery.com/jquery.get/
         *
         * Example:
         * ```JavaScript
         * $.spModal('get', 'test.php', {one: 1, two: 2, three: 3}).always(function () {
         *     console.log('This is always executed');
         * }).done(function (data) {
         *     console.log('This is executed on success requests');
         * }).fail(function () {
         *     console.log('This is executed on failed requests');
         * });
         * ```
         *
         * @param {Mixed} args Additional arguments
         *
         * @return {jQuery.Promise}
         */
        'get': function (args) {
            // Based on a Matthew Crumley solution,
            // as we can't use the .apply() method in conjunction with the 'new' operator
            // http://goo.gl/PRL0eZ (redirects to http://stackoverflow.com)
            function F(args) {
                return $.spModalRequestGet.apply(this, args);
            }
            F.prototype = $.spModalRequestGet.prototype;

            var req = new F(arguments);
            return req.send();
        },

        /**
         * Sends a POST request.
         *
         * This function uses internally the $.get function and accepts the same parameters. More info:
         * https://api.jquery.com/jquery.post/
         *
         * Example:
         * ```JavaScript
         * $.spModal('post', 'test.php', {one: 1, two: 2, three: 3}).always(function () {
         *     console.log('This is always executed');
         * }).done(function (data) {
         *     console.log('This is executed on success requests');
         * }).fail(function () {
         *     console.log('This is executed on failed requests');
         * });
         * ```
         *
         * @param {Mixed} args Additional arguments
         *
         * @return {jQuery.Promise}
         */
        'post': function (args) {
            // Based on a Matthew Crumley solution,
            // as we can't use the .apply() method in conjunction with the 'new' operator
            // http://goo.gl/PRL0eZ (redirects to http://stackoverflow.com)
            function F(args) {
                return $.spModalRequestPost.apply(this, args);
            }
            F.prototype = $.spModalRequestPost.prototype;

            var req = new F(arguments);
            return req.send();
        },

        /**
         * Sends a POST request and uploads files.
         *
         * Example:
         * ```JavaScript
         * var inputFile = $('#file');
         * inputFile.change(function () {
         *     $.spModal('upload', inputFile, 'test.php', {one: 1, two: 2}).done(function (data) {
         *         console.log(data);
         *     }).fail(function () {
         *         console.log('failed!');
         *     });
         * });
         * ```
         *
         * @param {jQuery.<HTMLInputElement>|String} input Input file(s)
         * @param {String}                           url   URL
         * @param {Object}                           data  Parameters (not required)
         *
         * @return {jQuery.Promise}
         */
        'upload': function (input, url, data) {
            var req = new $.spModalRequestUpload(input, url, data);
            return req.send();
        }
    };

    /**
     * Registers plugin.
     *
     * @param {String} methodName Method name
     * @param {Mixed}  args,...   Additional arguments (not required)
     *
     * @return {Mixed}
     */
    $.spModal = function (methodName, args) {
        var method = methods[methodName];
        var args = Array.prototype.slice.call(arguments, 1);

        if (method === undefined) {
            $.error('Method not found: ' + methodName);
        }

        return method.apply(this, args);
    };
})(jQuery);
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp'),
    gutil = require('gulp-util'),
    jshint = require('gulp-jshint'),
    mocha = require('gulp-mocha');

gulp.task('default', function() {
  gutil.log(gutil.colors.red('Specify a task'));
});

gulp.task('test', function() {
  return gulp.src('*.js')
    .pipe(mocha());
});

gulp.task('lint', function() {
  return gulp.src('*.js')
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('foo', function(cb) {
  setTimeout(function() {
    gutil.log('foo task');
    cb();
  }, 5000);
});

gulp.task('bar', function() {
  return gulp.src('fixtures/bad-format.js')
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('test', function(cb) {
  var Server = require('./index');

  var server = new Server();
  server.watch('*.js', ['foo']);
  server.watch('fixtures/*.js', ['bar']);
  server.registerHost('hotels.localhost', 'http://hotels.localhost');
  server.start(9810);
});
<commit_msg>Fix lint issue.<commit_after>'use strict';

var gulp = require('gulp'),
    gutil = require('gulp-util'),
    jshint = require('gulp-jshint'),
    mocha = require('gulp-mocha');

gulp.task('default', function() {
  gutil.log(gutil.colors.red('Specify a task'));
});

gulp.task('test', function() {
  return gulp.src('*.js')
    .pipe(mocha());
});

gulp.task('lint', function() {
  return gulp.src('*.js')
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('foo', function(cb) {
  setTimeout(function() {
    gutil.log('foo task');
    cb();
  }, 5000);
});

gulp.task('bar', function() {
  return gulp.src('fixtures/bad-format.js')
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('jshint-stylish'));
});

/* jshint unused:vars */
gulp.task('test', function(cb) {
  var Server = require('./index');

  var server = new Server();
  server.watch('*.js', ['foo']);
  server.watch('fixtures/*.js', ['bar']);
  server.registerHost('hotels.localhost', 'http://hotels.localhost');
  server.start(9810);
});
/* jshint unused:true */
<|endoftext|>


<commit_before>
/**
 * URL Input plugin for jQuery
 * @author Daniel Catarino Biscalchin
 *
 * Provides a widget for text inputs holding URL values.
 * It enforces the protocol and adds a link to test the URL.
 *
 * Basic usage: $('#my-text-input').urlinput()
 */

(function ($) {
  $.fn.urlinput = function (options) {
    // Set options based on theme or use default
    var theme = 'default';
    if (options && options.theme) {
      theme = options.theme;
    }
    var settings = $.extend({}, $.fn.urlinput.themes['default'],
                                $.fn.urlinput.themes[theme], options);

    // Add wrapper to input element
    var $widgetWrapper = $(settings.widgetWrapper);
    $widgetWrapper.addClass('urlinput-widget-wrapper');
    this.wrap($widgetWrapper);

    // Add extra classes to input element
    this.addClass('urlinput-field ' + settings.fieldClass);

    // Add icon before input
    if (settings.showFavicon) {
      var $iconWrapper = $(settings.faviconWrapper);
      $iconWrapper.addClass('urlinput-icon-wrapper');
      $iconWrapper.html('');
      this.before($iconWrapper);
    }

    // Add link after input
    var $linkWrapper = $(settings.linkWrapper);
    $linkWrapper.addClass('urlinput-link-wrapper');
    $linkWrapper.html('' + settings.linkText  + '');
    this.after($linkWrapper);

    // Iterate over each element to add a different value and handler
    this.each(function (i, elem) {
      var $this = $(this); // current element

      // Set default value
      var val = $this.val();
      var protocol = val.slice(0, 4);
      if (!(protocol == 'http')) {
        // Set val with http protocol
        val = 'http://' + val;
        $this.val(val);
      }

      // Add handler
      $this.change(function (ev) {
        var $this = $(this); // changed element
        var val = $this.val();

        // Add http protocol if not informed
        var protocol = val.slice(0, 4);
        if (!(protocol == 'http')) {
          // Set val with http protocol
          val = 'http://' + val;
          $this.val(val);
        }

        // Set link URL
        var $link = $this.next('.urlinput-link-wrapper').find('a').attr('href', $this.val());

        // Update favicon
        if (settings.showFavicon) {
          var faviconSrc = '//www.google.com/s2/favicons?domain=' + $link.prop('hostname');
          $this.prev('.urlinput-icon-wrapper').find('img').attr('src', faviconSrc);
        }
      });

      // Erase value when submitting if it has only the protocol
      $this.closest('form').submit(function (ev) {
        if ($this.val() == 'http://') {
          $this.val('');
        }
      });
    });

    return this;
  }

  $.fn.urlinput.themes = {
    default: {
      fieldClass: '',
      linkText: 'Try it!',
      linkClass: '',
      linkWrapper: $(''),
      showFavicon: true,
      faviconWrapper: $(''),
      widgetWrapper: $('

'),
    },
    bootstrap: {
      fieldClass: 'form-control',
      linkText: '',
      linkClass: 'btn btn-default',
      linkWrapper: $(''),
      faviconWrapper: $(''),
      widgetWrapper: $('

'),
    },
  };
}(jQuery));
<commit_msg>option to showLink<commit_after>
/**
 * URL Input plugin for jQuery
 * @author Daniel Catarino Biscalchin
 *
 * Provides a widget for text inputs holding URL values.
 * It enforces the protocol and adds a link to test the URL.
 *
 * Basic usage: $('#my-text-input').urlinput()
 */

(function ($) {
  $.fn.urlinput = function (options) {
    // Set options based on theme or use default
    var theme = 'default';
    if (options && options.theme) {
      theme = options.theme;
    }
    var settings = $.extend({}, $.fn.urlinput.themes['default'],
                                $.fn.urlinput.themes[theme], options);

    // Add wrapper to input element
    var $widgetWrapper = $(settings.widgetWrapper);
    $widgetWrapper.addClass('urlinput-widget-wrapper');
    this.wrap($widgetWrapper);

    // Add extra classes to input element
    this.addClass('urlinput-field ' + settings.fieldClass);

    // Add icon before input
    if (settings.showFavicon) {
      var $iconWrapper = $(settings.faviconWrapper);
      $iconWrapper.addClass('urlinput-icon-wrapper');
      $iconWrapper.html('');
      this.before($iconWrapper);
    }

    // Add link after input
    var $linkWrapper = $(settings.linkWrapper);
    $linkWrapper.addClass('urlinput-link-wrapper');
    $linkWrapper.html('' + settings.linkText  + '');
    this.after($linkWrapper);
    if (!settings.showLink) {
      // Favicon depends on the link, so it is just hidden
      $linkWrapper.hide();
    }

    // Iterate over each element to add a different value and handler
    this.each(function (i, elem) {
      var $this = $(this); // current element

      // Set default value
      var val = $this.val();
      var protocol = val.slice(0, 4);
      if (!(protocol == 'http')) {
        // Set val with http protocol
        val = 'http://' + val;
        $this.val(val);
      }

      // Add handler
      $this.change(function (ev) {
        var $this = $(this); // changed element
        var val = $this.val();

        // Add http protocol if not informed
        var protocol = val.slice(0, 4);
        if (!(protocol == 'http')) {
          // Set val with http protocol
          val = 'http://' + val;
          $this.val(val);
        }

        // Set link URL
        var $link = $this.next('.urlinput-link-wrapper').find('a').attr('href', $this.val());

        // Update favicon
        if (settings.showFavicon) {
          var faviconSrc = '//www.google.com/s2/favicons?domain=' + $link.prop('hostname');
          $this.prev('.urlinput-icon-wrapper').find('img').attr('src', faviconSrc);
        }
      });

      // Erase value when submitting if it has only the protocol
      $this.closest('form').submit(function (ev) {
        if ($this.val() == 'http://') {
          $this.val('');
        }
      });
    });

    return this;
  }

  $.fn.urlinput.themes = {
    default: {
      fieldClass: '',
      showLink: true,
      linkText: 'Try it!',
      linkClass: '',
      linkWrapper: $(''),
      showFavicon: true,
      faviconWrapper: $(''),
      widgetWrapper: $('

'),
    },
    bootstrap: {
      fieldClass: 'form-control',
      linkText: '',
      linkClass: 'btn btn-default',
      linkWrapper: $(''),
      faviconWrapper: $(''),
      widgetWrapper: $('

'),
    },
  };
}(jQuery));
<|endoftext|>


<commit_before>
// Graph object storage
var myGraph = {};

// Temporary gist data storage
var gistData = [];

// Select our active lineMode choice
var selectLineModeButton = function() {
  var index = $($('.line_mode.btn-group button.line_mode.btn[value="' + myLineMode + '"]')).attr('name');
  $('.line_mode.btn-group button.line_mode.btn.active').removeClass('active');
  $($('.line_mode.btn-group button.line_mode.btn')[index]).addClass('active');
};

// Select our active areaMode choice
var selectAreaModeButton = function() {
  var index = $($('.area_mode.btn-group button.area_mode.btn[value="' + myAreaMode + '"]')).attr('name');
  $('.area_mode.btn-group button.area_mode.btn.active').removeClass('active');
  $($('.area_mode.btn-group button.area_mode.btn')[index]).addClass('active');
};

// Select our active logMode choice
var selectLogModeButton = function() {
  var index = $($('.log_mode.btn-group button.log_mode.btn[value="' + myLogMode + '"]')).attr('name');
  $('.log_mode.btn-group button.log_mode.btn.active').removeClass('active');
  $($('.log_mode.btn-group button.log_mode.btn')[index || 1]).addClass('active');
};

// Select our active drawNullAsZero choice
var selectNullModeButton = function() {
  var index = $($('.null_mode.btn-group button.null_mode.btn[value="' + myNullMode + '"]')).attr('name');
  $('.null_mode.btn-group button.null_mode.btn.active').removeClass('active');
  $($('.null_mode.btn-group button.null_mode.btn')[index]).addClass('active');
};

// Store our updated settings
var updateGraph = function(cb) {
  var myUrl = window.location.pathname;
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {
      'overrides': {
        'lineMode': myLineMode,
        'areaMode': myAreaMode,
        'logBase': myLogMode,
        'drawNullAsZero': myNullMode,
        'target': myGraph.target
      }
    },
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'PUT',
    url: myUrl
  }).done(function(d) {
    console.log('Graph ' + window.location.pathname.split('/').pop() + ' successfully updated');
    cb();
  });
};

// Render the composer preview image and JSON editor
var renderComposerModal = function() {

  // construct our image config
  var composerImage = $.extend({}, myGraph.mergedConfig(), {
    height: 150,
    width: $('#composer_modal img#preview').width(),
    options: '&hideLegend=true',
    targets: myGraph.targets()
  });

  var composerImageUrl = constructGraphUrl(composerImage);

  $.ajax({
    beforeSend: function(xhr) {
      var creds = graphiteUser + ':' + graphitePass;
      if (creds.length > 1) {
        var bytes = Crypto.charenc.Binary.stringToBytes(creds);
        var base64 = Crypto.util.bytesToBase64(bytes);
        xhr.setRequestHeader('Authorization', 'Basic ' + base64);
      }
    },
    //error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'HEAD',
    url: composerImageUrl
  }).success(function() {
    // populate composer image and textarea
    $('#composer_modal img#preview').attr('src', composerImageUrl + '&height=' + composerImage.height + '&width=' + composerImage.width);
    $('#composer_modal textarea').text(JSON.stringify(myGraph.mergedConfig().target, null, "  "));
  });
};

// Grab configuration blob and construct our graph urls
var renderGraphs = function() {
  var myUrl = window.location.pathname;
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    url: myUrl
  }).done(function(d) {
    if (typeof d === 'undefined') {
      console.log('No graphs found');
    }

    myGraph = new Graph(d);
    var profileConfig = $.extend({}, myGraph.mergedConfig(), {height: 300, options: '&hideLegend=false'});

    updateLocalSettings(myGraph.mergedConfig());

    $('div.graphs').append('

');
    $('div.graphs div.row').append('

');
    $('div.graphs div.row div.graph').append('

');
    $('div.graph div.preview').append('');
    $('div.graph div.preview img').load(function() {
      // hide spinner on successful load
      $(this).parent('div.preview').css('background-image', 'none')
    }).error(function() {
      console.log('failed to load ' + $(this)[0].name);
      var broken_img = $(this);
      // hide spinner and show placeholder img
      broken_img.css('display', 'none');
      broken_img.parent('div.preview').css('background-image', 'url("/img/descartes-logo.png")').css('background-color', '#eee')
    });

    renderComposerModal();
    selectActiveIntervalButton();
    renderMetaInfo(d);
    renderDescription(d.description);
    renderTags();
    selectLineModeButton();
    selectAreaModeButton();
    selectLogModeButton();
    selectNullModeButton();
    $.ajax({
      accepts: {json: 'application/json'},
      cache: false,
      dataType: 'json',
      error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
      url: constructGraphUrl($.extend(profileConfig, {format: 'json'}))
    }).done(function(d) {
      gistData = d;
    });
  });
};

// Populate our info box
var renderMetaInfo = function(info) {
  $('span#owner').text(info.owner);
  $('span#created_at').text(info.created_at);
}

// Populate our description box
var renderDescription = function(description) {
  if ((typeof description === 'string') && (description.length > 0)) {
    myDescription = description;
    $('span#description').text(description);
  } else {
    $('span#description').html('Click here to add your own description of this graph.');
  }
};

// Reset description form
var resetDescriptionForm = function(desc) {
  $('div.description-wrapper span#description').removeClass('open').addClass('closed');
  $('div.description-wrapper span#description').children('textarea').remove();
  if ((typeof desc === 'string') && (desc.length > 0)) {
    $('div.description-wrapper span#description').text(desc);
  } else if (myDescription.length > 0) {
    $('div.description-wrapper span#description').text(myDescription);
  } else {
    $('div.description-wrapper span#description').append('Click here to add your own description of this graph.');
  }
  $('div.description-wrapper a').remove();
  return false;
};

// Populate our tags box
var renderTags = function() {
  gatherTags(function(tags) {
    $('div.tags-wrapper div.tags ul').remove();
    $('div.tags-wrapper div.tags span').remove();
    $('div.tags-wrapper div.tags').append('

');
    if ((typeof tags === 'object') && (tags.length > 0)) {
      for (var i in tags) {
        $('div.tags-wrapper div.tags ul').append('
 ' + tags[i].name + '
');
      }
    }
    $('div.tags-wrapper div.tags ul').append('
 Add a new tag...
');
  });
};

// Delete a tag
var deleteTag = function(id, cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'DELETE',
    url: window.location.pathname + '/tags/' + id
  }).done(function(d) {
    console.log('Tag ' + id + ' successfully deleted');
    cb();
  });
};

// Add a tag
var addTag = function(name, cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {'name': name},
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'POST',
    url: window.location.pathname + '/tags'
  }).done(function(d) {
    console.log('Tag ' + name + ' successfully added');
    cb();
  });
};

// Gather tags
var gatherTags = function(cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    url: window.location.pathname + '/tags'
  }).done(function(d) {
    cb(d);
  });
};

// Invert details button mode when activated
$(window).on('click', 'a.details.btn', function() {
  if ($('fieldset.in.collapse').length > 0) {
    resetFieldsetFormAndButtons($(this).attr('data-target'));
    $(this).text('Close Details').addClass('btn-inverse');
  } else {
    $(this).text('Details').removeClass('btn-inverse');
  }
});

// Convert description span into editable textarea
$('div.description-wrapper').on('click', 'span.closed#description', function() {
  $(this).unbind('click').removeClass('closed').addClass('open');
  $(this).html('<textarea class="description span4" rows="10">' + myDescription + '</textarea>');
  $(this).after('Update Description');
  $(this).after('Cancel');
  $(this).children('textarea').focus().select();
  return false;
});

// Reset description element on cancel
$('div.description-wrapper').on('click', 'a.description_cancel', resetDescriptionForm);

// Update description on submit
$('div.description-wrapper').on('click', 'a.description_submit', function() {
  var newDescription = $(this).parent().children('span#description').children('textarea').val();
  myDescription = newDescription;
  updateObjectAttributes({ 'description': newDescription }, function() {
    resetDescriptionForm(newDescription);
  });
  return false;
});

// Delete tag from list
$('div.tags-wrapper').on('click', 'a.tag_delete i', function() {
  var myTagId = $(this).parent().parent('li').attr('id');
  deleteTag(myTagId, function() {
    renderTags();
  });
  return false;
});

// Convert tag span into editable field
$('div.tags-wrapper').on('click', 'a.tag_add i', function() {
  $(this).parent('a').parent('li').children('span.tag_add').html('<input class="input-medium" type="text" name="new_tag"></input>');
  $(this).addClass('open');
  $('input[name="new_tag"]').focus();
});

// Add new tag
$('div.tags-wrapper div.tags').on('keypress', 'span.tag_add input[name="new_tag"]', function(e) {
  if (e.which === 13) {
    var myNewTag = $(this).val();
    addTag(myNewTag, function() {
      renderTags();
    });
    return false;
  }
});

// Reset tag input field on focusout
// XXX Potential race condition in that we call GET twice...
// XXX first after adding a tag (above), then here on focusout.
// XXX Not really a race condition per se, but a wasted call nonetheless.
$('div.tags-wrapper div.tags').on('focusout', 'span.tag_add input[name="new_tag"]', function() {
  renderTags();
});

// Update lineMode on selection
$('.line_mode.btn-group button.line_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myLineMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update areaMode on selection
$('.area_mode.btn-group button.area_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myAreaMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update logMode on selection
$('.log_mode.btn-group button.log_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myLogMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update drawNullAsZero on selection
$('.null_mode.btn-group button.null_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myNullMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// POST a new gist from profile
$('.tools.btn-group button.tools.btn.gist').click(function() {
  var graphUrl = $('.graph .preview img').attr('src');
  $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {'url': graphUrl, 'data': JSON.stringify(gistData)},
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'POST',
    url: window.location.pathname + '/gists'
  }).done(function(d) {
    $('div.header').before(
      '
' +
      '<button type="button" class="close" data-dismiss="alert">×</button>' +
      'Snapshot successfully created by ' + d.owner + ' on ' + d.created_at + '.'
    );
  }).fail(function(d, textStatus, errorThrown) {
    $('div.header').before(
      '
' +
      '<button type="button" class="close" data-dismiss="alert">×</button>' +
      'Unable to create snapshot: ' + errorThrown
    );
  });
  return false;
});

// Delete a graph
$('#destroy_modal .modal-footer button.delete').on('click', function() {
  deleteGraph($('div.graph div.preview img')[0].name, function() {
    console.log('deleted graph ' + $('div.graph div.preview img')[0].name);
    window.location.href = '/graphs';
  });
  return false;
});

// Bind composer textarea to edit and jsonlint
$('#composer_modal').on('input propertychange', 'textarea', function() {
  try {
    jsonlint.parse($(this).val());
    console.log('parses ok');
    myGraph.updateTargets(JSON.parse($(this).val()));
    renderComposerModal();
    $('#composer_modal button.targets_submit').removeClass('disabled');
  } catch(e) {
    console.log('parse failed');
    $('#composer_modal button.targets_submit').addClass('disabled');
  }
});

// Hidden key combo for composer modal
jwerty.key('alt+cmd+enter/alt+ctrl+c', function() {
  $('#composer_modal').modal('toggle');
});

// Edit graph targets
$('#composer_modal').on('click', 'button.targets_submit', function() {
  updateGraph(function() {
    $('#composer_modal').modal('toggle');
    renderComposerModal();
    clearGraphs();
    renderGraphs();
  });
});

// Not used in graph profile
var scrollNextPage = function() {
  return true;
}
<commit_msg>add alt+ctrl+enter for Windows<commit_after>
// Graph object storage
var myGraph = {};

// Temporary gist data storage
var gistData = [];

// Select our active lineMode choice
var selectLineModeButton = function() {
  var index = $($('.line_mode.btn-group button.line_mode.btn[value="' + myLineMode + '"]')).attr('name');
  $('.line_mode.btn-group button.line_mode.btn.active').removeClass('active');
  $($('.line_mode.btn-group button.line_mode.btn')[index]).addClass('active');
};

// Select our active areaMode choice
var selectAreaModeButton = function() {
  var index = $($('.area_mode.btn-group button.area_mode.btn[value="' + myAreaMode + '"]')).attr('name');
  $('.area_mode.btn-group button.area_mode.btn.active').removeClass('active');
  $($('.area_mode.btn-group button.area_mode.btn')[index]).addClass('active');
};

// Select our active logMode choice
var selectLogModeButton = function() {
  var index = $($('.log_mode.btn-group button.log_mode.btn[value="' + myLogMode + '"]')).attr('name');
  $('.log_mode.btn-group button.log_mode.btn.active').removeClass('active');
  $($('.log_mode.btn-group button.log_mode.btn')[index || 1]).addClass('active');
};

// Select our active drawNullAsZero choice
var selectNullModeButton = function() {
  var index = $($('.null_mode.btn-group button.null_mode.btn[value="' + myNullMode + '"]')).attr('name');
  $('.null_mode.btn-group button.null_mode.btn.active').removeClass('active');
  $($('.null_mode.btn-group button.null_mode.btn')[index]).addClass('active');
};

// Store our updated settings
var updateGraph = function(cb) {
  var myUrl = window.location.pathname;
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {
      'overrides': {
        'lineMode': myLineMode,
        'areaMode': myAreaMode,
        'logBase': myLogMode,
        'drawNullAsZero': myNullMode,
        'target': myGraph.target
      }
    },
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'PUT',
    url: myUrl
  }).done(function(d) {
    console.log('Graph ' + window.location.pathname.split('/').pop() + ' successfully updated');
    cb();
  });
};

// Render the composer preview image and JSON editor
var renderComposerModal = function() {

  // construct our image config
  var composerImage = $.extend({}, myGraph.mergedConfig(), {
    height: 150,
    width: $('#composer_modal img#preview').width(),
    options: '&hideLegend=true',
    targets: myGraph.targets()
  });

  var composerImageUrl = constructGraphUrl(composerImage);

  $.ajax({
    beforeSend: function(xhr) {
      var creds = graphiteUser + ':' + graphitePass;
      if (creds.length > 1) {
        var bytes = Crypto.charenc.Binary.stringToBytes(creds);
        var base64 = Crypto.util.bytesToBase64(bytes);
        xhr.setRequestHeader('Authorization', 'Basic ' + base64);
      }
    },
    //error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'HEAD',
    url: composerImageUrl
  }).success(function() {
    // populate composer image and textarea
    $('#composer_modal img#preview').attr('src', composerImageUrl + '&height=' + composerImage.height + '&width=' + composerImage.width);
    $('#composer_modal textarea').text(JSON.stringify(myGraph.mergedConfig().target, null, "  "));
  });
};

// Grab configuration blob and construct our graph urls
var renderGraphs = function() {
  var myUrl = window.location.pathname;
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    url: myUrl
  }).done(function(d) {
    if (typeof d === 'undefined') {
      console.log('No graphs found');
    }

    myGraph = new Graph(d);
    var profileConfig = $.extend({}, myGraph.mergedConfig(), {height: 300, options: '&hideLegend=false'});

    updateLocalSettings(myGraph.mergedConfig());

    $('div.graphs').append('

');
    $('div.graphs div.row').append('

');
    $('div.graphs div.row div.graph').append('

');
    $('div.graph div.preview').append('');
    $('div.graph div.preview img').load(function() {
      // hide spinner on successful load
      $(this).parent('div.preview').css('background-image', 'none')
    }).error(function() {
      console.log('failed to load ' + $(this)[0].name);
      var broken_img = $(this);
      // hide spinner and show placeholder img
      broken_img.css('display', 'none');
      broken_img.parent('div.preview').css('background-image', 'url("/img/descartes-logo.png")').css('background-color', '#eee')
    });

    renderComposerModal();
    selectActiveIntervalButton();
    renderMetaInfo(d);
    renderDescription(d.description);
    renderTags();
    selectLineModeButton();
    selectAreaModeButton();
    selectLogModeButton();
    selectNullModeButton();
    $.ajax({
      accepts: {json: 'application/json'},
      cache: false,
      dataType: 'json',
      error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
      url: constructGraphUrl($.extend(profileConfig, {format: 'json'}))
    }).done(function(d) {
      gistData = d;
    });
  });
};

// Populate our info box
var renderMetaInfo = function(info) {
  $('span#owner').text(info.owner);
  $('span#created_at').text(info.created_at);
}

// Populate our description box
var renderDescription = function(description) {
  if ((typeof description === 'string') && (description.length > 0)) {
    myDescription = description;
    $('span#description').text(description);
  } else {
    $('span#description').html('Click here to add your own description of this graph.');
  }
};

// Reset description form
var resetDescriptionForm = function(desc) {
  $('div.description-wrapper span#description').removeClass('open').addClass('closed');
  $('div.description-wrapper span#description').children('textarea').remove();
  if ((typeof desc === 'string') && (desc.length > 0)) {
    $('div.description-wrapper span#description').text(desc);
  } else if (myDescription.length > 0) {
    $('div.description-wrapper span#description').text(myDescription);
  } else {
    $('div.description-wrapper span#description').append('Click here to add your own description of this graph.');
  }
  $('div.description-wrapper a').remove();
  return false;
};

// Populate our tags box
var renderTags = function() {
  gatherTags(function(tags) {
    $('div.tags-wrapper div.tags ul').remove();
    $('div.tags-wrapper div.tags span').remove();
    $('div.tags-wrapper div.tags').append('

');
    if ((typeof tags === 'object') && (tags.length > 0)) {
      for (var i in tags) {
        $('div.tags-wrapper div.tags ul').append('
 ' + tags[i].name + '
');
      }
    }
    $('div.tags-wrapper div.tags ul').append('
 Add a new tag...
');
  });
};

// Delete a tag
var deleteTag = function(id, cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'DELETE',
    url: window.location.pathname + '/tags/' + id
  }).done(function(d) {
    console.log('Tag ' + id + ' successfully deleted');
    cb();
  });
};

// Add a tag
var addTag = function(name, cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {'name': name},
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'POST',
    url: window.location.pathname + '/tags'
  }).done(function(d) {
    console.log('Tag ' + name + ' successfully added');
    cb();
  });
};

// Gather tags
var gatherTags = function(cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    url: window.location.pathname + '/tags'
  }).done(function(d) {
    cb(d);
  });
};

// Invert details button mode when activated
$(window).on('click', 'a.details.btn', function() {
  if ($('fieldset.in.collapse').length > 0) {
    resetFieldsetFormAndButtons($(this).attr('data-target'));
    $(this).text('Close Details').addClass('btn-inverse');
  } else {
    $(this).text('Details').removeClass('btn-inverse');
  }
});

// Convert description span into editable textarea
$('div.description-wrapper').on('click', 'span.closed#description', function() {
  $(this).unbind('click').removeClass('closed').addClass('open');
  $(this).html('<textarea class="description span4" rows="10">' + myDescription + '</textarea>');
  $(this).after('Update Description');
  $(this).after('Cancel');
  $(this).children('textarea').focus().select();
  return false;
});

// Reset description element on cancel
$('div.description-wrapper').on('click', 'a.description_cancel', resetDescriptionForm);

// Update description on submit
$('div.description-wrapper').on('click', 'a.description_submit', function() {
  var newDescription = $(this).parent().children('span#description').children('textarea').val();
  myDescription = newDescription;
  updateObjectAttributes({ 'description': newDescription }, function() {
    resetDescriptionForm(newDescription);
  });
  return false;
});

// Delete tag from list
$('div.tags-wrapper').on('click', 'a.tag_delete i', function() {
  var myTagId = $(this).parent().parent('li').attr('id');
  deleteTag(myTagId, function() {
    renderTags();
  });
  return false;
});

// Convert tag span into editable field
$('div.tags-wrapper').on('click', 'a.tag_add i', function() {
  $(this).parent('a').parent('li').children('span.tag_add').html('<input class="input-medium" type="text" name="new_tag"></input>');
  $(this).addClass('open');
  $('input[name="new_tag"]').focus();
});

// Add new tag
$('div.tags-wrapper div.tags').on('keypress', 'span.tag_add input[name="new_tag"]', function(e) {
  if (e.which === 13) {
    var myNewTag = $(this).val();
    addTag(myNewTag, function() {
      renderTags();
    });
    return false;
  }
});

// Reset tag input field on focusout
// XXX Potential race condition in that we call GET twice...
// XXX first after adding a tag (above), then here on focusout.
// XXX Not really a race condition per se, but a wasted call nonetheless.
$('div.tags-wrapper div.tags').on('focusout', 'span.tag_add input[name="new_tag"]', function() {
  renderTags();
});

// Update lineMode on selection
$('.line_mode.btn-group button.line_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myLineMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update areaMode on selection
$('.area_mode.btn-group button.area_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myAreaMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update logMode on selection
$('.log_mode.btn-group button.log_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myLogMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update drawNullAsZero on selection
$('.null_mode.btn-group button.null_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myNullMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// POST a new gist from profile
$('.tools.btn-group button.tools.btn.gist').click(function() {
  var graphUrl = $('.graph .preview img').attr('src');
  $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {'url': graphUrl, 'data': JSON.stringify(gistData)},
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'POST',
    url: window.location.pathname + '/gists'
  }).done(function(d) {
    $('div.header').before(
      '
' +
      '<button type="button" class="close" data-dismiss="alert">×</button>' +
      'Snapshot successfully created by ' + d.owner + ' on ' + d.created_at + '.'
    );
  }).fail(function(d, textStatus, errorThrown) {
    $('div.header').before(
      '
' +
      '<button type="button" class="close" data-dismiss="alert">×</button>' +
      'Unable to create snapshot: ' + errorThrown
    );
  });
  return false;
});

// Delete a graph
$('#destroy_modal .modal-footer button.delete').on('click', function() {
  deleteGraph($('div.graph div.preview img')[0].name, function() {
    console.log('deleted graph ' + $('div.graph div.preview img')[0].name);
    window.location.href = '/graphs';
  });
  return false;
});

// Bind composer textarea to edit and jsonlint
$('#composer_modal').on('input propertychange', 'textarea', function() {
  try {
    jsonlint.parse($(this).val());
    console.log('parses ok');
    myGraph.updateTargets(JSON.parse($(this).val()));
    renderComposerModal();
    $('#composer_modal button.targets_submit').removeClass('disabled');
  } catch(e) {
    console.log('parse failed');
    $('#composer_modal button.targets_submit').addClass('disabled');
  }
});

// Hidden key combo for composer modal
jwerty.key('alt+cmd+enter/alt+ctrl+enter', function() {
  $('#composer_modal').modal('toggle');
});

// Edit graph targets
$('#composer_modal').on('click', 'button.targets_submit', function() {
  updateGraph(function() {
    $('#composer_modal').modal('toggle');
    renderComposerModal();
    clearGraphs();
    renderGraphs();
  });
});

// Not used in graph profile
var scrollNextPage = function() {
  return true;
}
<|endoftext|>


<commit_before>define([
    'artist/artist'
], function(Artist) {
    'use strict';

    describe('Artist Init', function() {
        it('it can create an Artist', function() {
            var artist = new Artist();
            artist.setName('Bob Dylan');

            expect(artist.name).toBe('Bob Dylan');
        });

        it('it can set Artist as featured', function() {
            var artist = new Artist();
            artist.setName('Bob Dylan').setFeatured();

            expect(artist.isFeatured()).toBe(true);
        });
    });

});<commit_msg>changed testing a bit, to setup each time new object.<commit_after>define([
    'artist/artist'
], function(Artist) {
    'use strict';

    var artist;

    beforeEach(function() {
        artist = new Artist();
    });

    describe('Artist Init', function() {
        it('it can create an Artist', function() {
            artist.setName('Bob Dylan');

            expect(artist.name).toBe('Bob Dylan');
        });

        it('it can set Artist as featured', function() {
            artist.setName('Bob Dylan').setFeatured();

            expect(artist.isFeatured()).toBe(true);
        });
    });

});<|endoftext|>


<commit_before>(function () {
    // simulates abstract class
    DO = { }
}());<commit_msg>ajusta objeto DO<commit_after>var DO = {};

(function () {
    // simulates abstract class
    DO = {}
}(DO));<|endoftext|>


<commit_before>APP.applicationController = (function () {
    'use strict';

    var fastClick,
		iOSPrivateBrowsing;

    function offlineWarning() {
        alert("This feature is only available online.");
    }

    function pageNotFound() {
        alert("That page you were looking for cannot be found.");
    }

    function showHome() {
        $("#body").html(APP.templates.home());

        // Load up the last cached copy of the news
        APP.articlesController.showArticleList();

        $('#refreshButton').click(function () {

            // If the user is offline, don't bother trying to synchronize
            if (navigator && navigator.onLine === false) {
                offlineWarning();
            } else {
                APP.articlesController.synchronizeWithServer(function failureCallback() {
                    alert("This feature is not available offline");
                });
            }
        });
    }

    function showArticle(id) {
        $("#body").html(APP.templates.articleLoading());
        APP.articlesController.showArticle(id);
    }

    function route() {
        var page = window.location.hash;
        if (page) {
            page = page.substring(1);
        }
        if (page.length > 0) {
            if (parseInt(page, 10) > 0) {
                showArticle(parseInt(page, 10));
            } else {
                pageNotFound();
            }
        } else {
            showHome();
        }
    }

    function initialize(resources) {

        // Listen to the hash tag changing
        if ("onhashchange" in window) {
            $(window).bind("hashchange", route);

        // Support for old IE (which didn't have hash change)
        } else {
            (function () {
                var lastHash = window.location.hash;
                window.setInterval(function () {
                    if (window.location.hash !== lastHash) {
                        lastHash = window.location.hash;
                        route();
                    }
                }, 100);
            }());
        }

        // Set up FastClick
        fastClick = new FastClick(document.body);

        // Inject CSS Into the DOM
        $("head").append("<style>" + resources.css + "</style>");

        // Create app elements
        $("body").html(APP.templates.application());

        // Remove our loading splash screen
        $("#loading").remove();

        route();
    }

    // This is to our webapp what main() is to C, $(document).ready is to jQuery, etc
    function start(resources, storeResources) {

		// Try to detect whether iOS private browsing mode is enabled
		try {
			localStorage.test = '';
			localStorage.removeItem('item');
		} catch (exception) {
			if (exception.code === 22) {
				iOSPrivateBrowsing = true;
			}
		}

		if (iOSPrivateBrowsing) {
			return APP.network.start(function networkSuccess() {
                APP.database = APP.network;
                initialize(resources);
            });
		}

        // When indexedDB available, use it!
        APP.indexedDB.start(function indexedDBSuccess() {
            APP.database = APP.indexedDB;
            initialize(resources);

            // When indexedDB is not available, fallback to trying websql
        }, function indexedDBFailure() {
            APP.webSQL.start(function webSQLSuccess() {
                APP.database = APP.webSQL;
                initialize(resources);

            // When webSQL not available, fall back to using the network
            }, function webSQLFailure() {
                APP.network.start(function networkSuccess() {
                    APP.database = APP.network;
                    initialize(resources);
                });
            });
        });

        if (storeResources && window['localStorage']) {
            localStorage.resources = JSON.stringify(resources);
        }
    }

    return {
        start: start
    };
}());
<commit_msg>Tidy up - how have I not spotted this before<commit_after>APP.applicationController = (function () {
    'use strict';

    var fastClick,
		iOSPrivateBrowsing;

    function offlineWarning() {
        alert("This feature is only available online.");
    }

    function pageNotFound() {
        alert("That page you were looking for cannot be found.");
    }

    function showHome() {
        $("#body").html(APP.templates.home());

        // Load up the last cached copy of the news
        APP.articlesController.showArticleList();

        $('#refreshButton').click(function () {

            // If the user is offline, don't bother trying to synchronize
            if (navigator && navigator.onLine === false) {
                offlineWarning();
            } else {
                APP.articlesController.synchronizeWithServer(offlineWarning);
            }
        });
    }

    function showArticle(id) {
        $("#body").html(APP.templates.articleLoading());
        APP.articlesController.showArticle(id);
    }

    function route() {
        var page = window.location.hash;
        if (page) {
            page = page.substring(1);
        }
        if (page.length > 0) {
            if (parseInt(page, 10) > 0) {
                showArticle(parseInt(page, 10));
            } else {
                pageNotFound();
            }
        } else {
            showHome();
        }
    }

    function initialize(resources) {

        // Listen to the hash tag changing
        if ("onhashchange" in window) {
            $(window).bind("hashchange", route);

        // Support for old IE (which didn't have hash change)
        } else {
            (function () {
                var lastHash = window.location.hash;
                window.setInterval(function () {
                    if (window.location.hash !== lastHash) {
                        lastHash = window.location.hash;
                        route();
                    }
                }, 100);
            }());
        }

        // Set up FastClick
        fastClick = new FastClick(document.body);

        // Inject CSS Into the DOM
        $("head").append("<style>" + resources.css + "</style>");

        // Create app elements
        $("body").html(APP.templates.application());

        // Remove our loading splash screen
        $("#loading").remove();

        route();
    }

    // This is to our webapp what main() is to C, $(document).ready is to jQuery, etc
    function start(resources, storeResources) {

		// Try to detect whether iOS private browsing mode is enabled
		try {
			localStorage.test = '';
			localStorage.removeItem('item');
		} catch (exception) {
			if (exception.code === 22) {
				iOSPrivateBrowsing = true;
			}
		}

		if (iOSPrivateBrowsing) {
			return APP.network.start(function networkSuccess() {
                APP.database = APP.network;
                initialize(resources);
            });
		}

        // When indexedDB available, use it!
        APP.indexedDB.start(function indexedDBSuccess() {
            APP.database = APP.indexedDB;
            initialize(resources);

            // When indexedDB is not available, fallback to trying websql
        }, function indexedDBFailure() {
            APP.webSQL.start(function webSQLSuccess() {
                APP.database = APP.webSQL;
                initialize(resources);

            // When webSQL not available, fall back to using the network
            }, function webSQLFailure() {
                APP.network.start(function networkSuccess() {
                    APP.database = APP.network;
                    initialize(resources);
                });
            });
        });

        if (storeResources && window['localStorage']) {
            localStorage.resources = JSON.stringify(resources);
        }
    }

    return {
        start: start
    };
}());
<|endoftext|>