mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 21:27:40 +00:00
Merge 1.1.0 changes back to master.
This commit is contained in:
@@ -18,11 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A directive which implements a color input field, leveraging the "Pickr"
|
* A directive which implements a color input field. If the underlying color
|
||||||
* color picker. If the "Picker" color picker cannot be used because it relies
|
* picker implementation cannot be used due to a lack of browser support, this
|
||||||
* on JavaScript features not supported by the browser (Internet Explorer), a
|
|
||||||
* "guacInputColorUnavailable" event will be emitted up the scope, and this
|
|
||||||
* directive will become read-only, functioning essentially as a color preview.
|
* directive will become read-only, functioning essentially as a color preview.
|
||||||
|
*
|
||||||
|
* @see colorPickerService
|
||||||
*/
|
*/
|
||||||
angular.module('form').directive('guacInputColor', [function guacInputColor() {
|
angular.module('form').directive('guacInputColor', [function guacInputColor() {
|
||||||
|
|
||||||
@@ -59,17 +59,12 @@ angular.module('form').directive('guacInputColor', [function guacInputColor() {
|
|||||||
function guacInputColorController($scope, $element, $injector) {
|
function guacInputColorController($scope, $element, $injector) {
|
||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
var $q = $injector.get('$q');
|
var colorPickerService = $injector.get('colorPickerService');
|
||||||
var $translate = $injector.get('$translate');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the color picker ("Pickr") cannot be used. In general, all
|
* @borrows colorPickerService.isAvailable()
|
||||||
* browsers should support Pickr with the exception of Internet
|
|
||||||
* Explorer.
|
|
||||||
*
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
*/
|
||||||
$scope.colorPickerUnavailable = false;
|
$scope.isColorPickerAvailable = colorPickerService.isAvailable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the color currently selected is "dark" in the sense
|
* Returns whether the color currently selected is "dark" in the sense
|
||||||
@@ -102,98 +97,18 @@ angular.module('form').directive('guacInputColor', [function guacInputColor() {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Init color picker after required translation strings are available
|
/**
|
||||||
$q.all({
|
* Prompts the user to choose a color by displaying a color selection
|
||||||
'save' : $translate('APP.ACTION_SAVE'),
|
* dialog. If the user chooses a color, this directive's model is
|
||||||
'cancel' : $translate('APP.ACTION_CANCEL')
|
* automatically updated. If the user cancels the dialog, the model is
|
||||||
}).then(function stringsRetrieved(strings) {
|
* left untouched.
|
||||||
|
*/
|
||||||
try {
|
$scope.selectColor = function selectColor() {
|
||||||
|
colorPickerService.selectColor($element[0], $scope.model, $scope.palette)
|
||||||
/**
|
.then(function colorSelected(color) {
|
||||||
* An instance of the "Pickr" color picker, bound to the underlying
|
$scope.model = color;
|
||||||
* element of this directive.
|
}, angular.noop);
|
||||||
*
|
};
|
||||||
* @type Pickr
|
|
||||||
*/
|
|
||||||
var pickr = Pickr.create({
|
|
||||||
|
|
||||||
// Bind color picker to the underlying element of this directive
|
|
||||||
el : $element[0],
|
|
||||||
|
|
||||||
// Wrap color picker dialog in Guacamole-specific class for
|
|
||||||
// sake of additional styling
|
|
||||||
appClass : 'guac-input-color-picker',
|
|
||||||
|
|
||||||
// Display color details as hex
|
|
||||||
defaultRepresentation : 'HEX',
|
|
||||||
|
|
||||||
// Use "monolith" theme, as a nice balance between "nano" (does
|
|
||||||
// not work in Internet Explorer) and "classic" (too big)
|
|
||||||
theme : 'monolith',
|
|
||||||
|
|
||||||
// Leverage the container element as the button which shows the
|
|
||||||
// picker, relying on our own styling for that button
|
|
||||||
useAsButton : true,
|
|
||||||
appendToBody : true,
|
|
||||||
|
|
||||||
// Do not include opacity controls
|
|
||||||
lockOpacity : true,
|
|
||||||
|
|
||||||
// Include a selection of palette entries for convenience and
|
|
||||||
// reference
|
|
||||||
swatches : $scope.palette || [],
|
|
||||||
|
|
||||||
components: {
|
|
||||||
|
|
||||||
// Include hue and color preview controls
|
|
||||||
preview : true,
|
|
||||||
hue : true,
|
|
||||||
|
|
||||||
// Display only a text color input field and the save and
|
|
||||||
// cancel buttons (no clear button)
|
|
||||||
interaction: {
|
|
||||||
input : true,
|
|
||||||
save : true,
|
|
||||||
cancel : true
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
// Use translation strings for buttons
|
|
||||||
strings : strings
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Hide color picker after user clicks "cancel"
|
|
||||||
pickr.on('cancel', function colorChangeCanceled() {
|
|
||||||
pickr.hide();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Keep model in sync with changes to the color picker
|
|
||||||
pickr.on('save', function colorChanged(color) {
|
|
||||||
$scope.$evalAsync(function updateModel() {
|
|
||||||
$scope.model = color.toHEXA().toString();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Keep color picker in sync with changes to the model
|
|
||||||
pickr.on('init', function pickrReady(color) {
|
|
||||||
$scope.$watch('model', function modelChanged(model) {
|
|
||||||
pickr.setColor(model);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the "Pickr" color picker cannot be loaded (Internet Explorer),
|
|
||||||
// let the scope above us know
|
|
||||||
catch (e) {
|
|
||||||
$scope.colorPickerUnavailable = true;
|
|
||||||
$scope.$emit('guacInputColorUnavailable', e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, angular.noop);
|
|
||||||
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service for prompting the user to choose a color using the "Pickr" color
|
||||||
|
* picker. As the Pickr color picker might not be available if the JavaScript
|
||||||
|
* features it requires are not supported by the browser (Internet Explorer),
|
||||||
|
* the isAvailable() function should be used to test for usability.
|
||||||
|
*/
|
||||||
|
angular.module('form').provider('colorPickerService', function colorPickerServiceProvider() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A singleton instance of the "Pickr" color picker, shared by all users of
|
||||||
|
* this service. Pickr does not initialize synchronously, nor is it
|
||||||
|
* supported by all browsers. If Pickr is not yet initialized, or is
|
||||||
|
* unsupported, this will be null.
|
||||||
|
*
|
||||||
|
* @type {Pickr}
|
||||||
|
*/
|
||||||
|
var pickr = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether Pickr has completed initialization.
|
||||||
|
*
|
||||||
|
* @type {Boolean}
|
||||||
|
*/
|
||||||
|
var pickrInitComplete = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HTML element to provide to Pickr as the root element.
|
||||||
|
*
|
||||||
|
* @type {HTMLDivElement}
|
||||||
|
*/
|
||||||
|
var pickerContainer = document.createElement('div');
|
||||||
|
pickerContainer.className = 'shared-color-picker';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance of Deferred which represents an active request for the
|
||||||
|
* user to choose a color. The promise associated with the Deferred will
|
||||||
|
* be resolved with the chosen color once a color is chosen, and rejected
|
||||||
|
* if the request is cancelled or Pickr is not available. If no request is
|
||||||
|
* active, this will be null.
|
||||||
|
*
|
||||||
|
* @type {Deferred}
|
||||||
|
*/
|
||||||
|
var activeRequest = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the current active request with the given color value. If no
|
||||||
|
* color value is provided, the active request is rejected. If no request
|
||||||
|
* is active, this function has no effect.
|
||||||
|
*
|
||||||
|
* @param {String} [color]
|
||||||
|
* The color value to resolve the active request with.
|
||||||
|
*/
|
||||||
|
var completeActiveRequest = function completeActiveRequest(color) {
|
||||||
|
if (activeRequest) {
|
||||||
|
|
||||||
|
// Hide color picker, if shown
|
||||||
|
pickr.hide();
|
||||||
|
|
||||||
|
// Resolve/reject active request depending on value provided
|
||||||
|
if (color)
|
||||||
|
activeRequest.resolve(color);
|
||||||
|
else
|
||||||
|
activeRequest.reject();
|
||||||
|
|
||||||
|
// No active request
|
||||||
|
activeRequest = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
pickr = Pickr.create({
|
||||||
|
|
||||||
|
// Bind color picker to the container element
|
||||||
|
el : pickerContainer,
|
||||||
|
|
||||||
|
// Wrap color picker dialog in Guacamole-specific class for
|
||||||
|
// sake of additional styling
|
||||||
|
appClass : 'guac-input-color-picker',
|
||||||
|
|
||||||
|
'default' : '#000000',
|
||||||
|
|
||||||
|
// Display color details as hex
|
||||||
|
defaultRepresentation : 'HEX',
|
||||||
|
|
||||||
|
// Use "monolith" theme, as a nice balance between "nano" (does
|
||||||
|
// not work in Internet Explorer) and "classic" (too big)
|
||||||
|
theme : 'monolith',
|
||||||
|
|
||||||
|
// Leverage the container element as the button which shows the
|
||||||
|
// picker, relying on our own styling for that button
|
||||||
|
useAsButton : true,
|
||||||
|
appendToBody : true,
|
||||||
|
|
||||||
|
// Do not include opacity controls
|
||||||
|
lockOpacity : true,
|
||||||
|
|
||||||
|
// Include a selection of palette entries for convenience and
|
||||||
|
// reference
|
||||||
|
swatches : [],
|
||||||
|
|
||||||
|
components: {
|
||||||
|
|
||||||
|
// Include hue and color preview controls
|
||||||
|
preview : true,
|
||||||
|
hue : true,
|
||||||
|
|
||||||
|
// Display only a text color input field and the save and
|
||||||
|
// cancel buttons (no clear button)
|
||||||
|
interaction: {
|
||||||
|
input : true,
|
||||||
|
save : true,
|
||||||
|
cancel : true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hide color picker after user clicks "cancel"
|
||||||
|
pickr.on('cancel', function colorChangeCanceled() {
|
||||||
|
completeActiveRequest();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keep model in sync with changes to the color picker
|
||||||
|
pickr.on('save', function colorChanged(color) {
|
||||||
|
completeActiveRequest(color.toHEXA().toString());
|
||||||
|
activeRequest = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keep color picker in sync with changes to the model
|
||||||
|
pickr.on('init', function pickrReady() {
|
||||||
|
pickrInitComplete = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
// If the "Pickr" color picker cannot be loaded (Internet Explorer),
|
||||||
|
// the available flag will remain set to false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Factory method required by provider
|
||||||
|
this.$get = ['$injector', function colorPickerServiceFactory($injector) {
|
||||||
|
|
||||||
|
// Required services
|
||||||
|
var $q = $injector.get('$q');
|
||||||
|
var $translate = $injector.get('$translate');
|
||||||
|
|
||||||
|
var service = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Promise which is resolved when Pickr initialization has completed
|
||||||
|
* and rejected if Pickr cannot be used.
|
||||||
|
*
|
||||||
|
* @type {Promise}
|
||||||
|
*/
|
||||||
|
var pickrPromise = (function getPickr() {
|
||||||
|
|
||||||
|
var deferred = $q.defer();
|
||||||
|
|
||||||
|
// Resolve promise when Pickr has completed initialization
|
||||||
|
if (pickrInitComplete)
|
||||||
|
deferred.resolve();
|
||||||
|
else if (pickr)
|
||||||
|
pickr.on('init', deferred.resolve);
|
||||||
|
|
||||||
|
// Reject promise if Pickr cannot be used at all
|
||||||
|
else
|
||||||
|
deferred.reject();
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the underlying color picker (Pickr) can be used by
|
||||||
|
* calling selectColor(). If the browser cannot support the color
|
||||||
|
* picker, false is returned.
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
* true if the underlying color picker can be used by calling
|
||||||
|
* selectColor(), false otherwise.
|
||||||
|
*/
|
||||||
|
service.isAvailable = function isAvailable() {
|
||||||
|
return !!pickr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user to choose a color, returning the color chosen via a
|
||||||
|
* Promise.
|
||||||
|
*
|
||||||
|
* @param {Element} element
|
||||||
|
* The element that the user interacted with to indicate their
|
||||||
|
* desire to choose a color.
|
||||||
|
*
|
||||||
|
* @param {String} current
|
||||||
|
* The color that should be selected by default, in standard
|
||||||
|
* 6-digit hexadecimal RGB format, including "#" prefix.
|
||||||
|
*
|
||||||
|
* @param {String[]} [palette]
|
||||||
|
* An array of color choices which should be exposed to the user
|
||||||
|
* within the color chooser for convenience. Each color must be in
|
||||||
|
* standard 6-digit hexadecimal RGB format, including "#" prefix.
|
||||||
|
*
|
||||||
|
* @returns {Promise.<String>}
|
||||||
|
* A Promise which is resolved with the color chosen by the user,
|
||||||
|
* in standard 6-digit hexadecimal RGB format with "#" prefix, and
|
||||||
|
* rejected if the selection operation was cancelled or the color
|
||||||
|
* picker cannot be used.
|
||||||
|
*/
|
||||||
|
service.selectColor = function selectColor(element, current, palette) {
|
||||||
|
|
||||||
|
// Show picker once the relevant translation strings have been
|
||||||
|
// retrieved and Pickr is ready for use
|
||||||
|
return $q.all({
|
||||||
|
'saveString' : $translate('APP.ACTION_SAVE'),
|
||||||
|
'cancelString' : $translate('APP.ACTION_CANCEL'),
|
||||||
|
'pickr' : pickrPromise
|
||||||
|
}).then(function dependenciesReady(deps) {
|
||||||
|
|
||||||
|
// Cancel any active request
|
||||||
|
completeActiveRequest();
|
||||||
|
|
||||||
|
// Reset state of color picker to provided parameters
|
||||||
|
pickr.setColor(current);
|
||||||
|
element.appendChild(pickerContainer);
|
||||||
|
|
||||||
|
// Assign translated strings to button text
|
||||||
|
var pickrRoot = pickr.getRoot();
|
||||||
|
pickrRoot.interaction.save.value = deps.saveString;
|
||||||
|
pickrRoot.interaction.cancel.value = deps.cancelString;
|
||||||
|
|
||||||
|
// Replace all color swatches with the palette of colors given
|
||||||
|
while (pickr.removeSwatch(0)) {}
|
||||||
|
angular.forEach(palette, pickr.addSwatch.bind(pickr));
|
||||||
|
|
||||||
|
// Show color picker and wait for user to complete selection
|
||||||
|
activeRequest = $q.defer();
|
||||||
|
pickr.show();
|
||||||
|
return activeRequest.promise;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return service;
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
});
|
@@ -220,10 +220,45 @@ angular.module('form').provider('formService', function formServiceProvider() {
|
|||||||
var $q = $injector.get('$q');
|
var $q = $injector.get('$q');
|
||||||
var $templateRequest = $injector.get('$templateRequest');
|
var $templateRequest = $injector.get('$templateRequest');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of module name to the injector instance created for that module.
|
||||||
|
*
|
||||||
|
* @type {Object.<String, injector>}
|
||||||
|
*/
|
||||||
|
var injectors = {};
|
||||||
|
|
||||||
var service = {};
|
var service = {};
|
||||||
|
|
||||||
service.fieldTypes = provider.fieldTypes;
|
service.fieldTypes = provider.fieldTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the name of a module, returns an injector instance which
|
||||||
|
* injects dependencies within that module. A new injector may be
|
||||||
|
* created and initialized if no such injector has yet been requested.
|
||||||
|
* If the injector available to formService already includes the
|
||||||
|
* requested module, that injector will simply be returned.
|
||||||
|
*
|
||||||
|
* @param {String} module
|
||||||
|
* The name of the module to produce an injector for.
|
||||||
|
*
|
||||||
|
* @returns {injector}
|
||||||
|
* An injector instance which injects dependencies for the given
|
||||||
|
* module.
|
||||||
|
*/
|
||||||
|
var getInjector = function getInjector(module) {
|
||||||
|
|
||||||
|
// Use the formService's injector if possible
|
||||||
|
if ($injector.modules[module])
|
||||||
|
return $injector;
|
||||||
|
|
||||||
|
// If the formService's injector does not include the requested
|
||||||
|
// module, create the necessary injector, reusing that injector for
|
||||||
|
// future calls
|
||||||
|
injectors[module] = injectors[module] || angular.injector(['ng', module]);
|
||||||
|
return injectors[module];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles and links the field associated with the given name to the given
|
* Compiles and links the field associated with the given name to the given
|
||||||
* scope, producing a distinct and independent DOM Element which functions
|
* scope, producing a distinct and independent DOM Element which functions
|
||||||
@@ -304,7 +339,7 @@ angular.module('form').provider('formService', function formServiceProvider() {
|
|||||||
|
|
||||||
// Populate scope using defined controller
|
// Populate scope using defined controller
|
||||||
if (fieldType.module && fieldType.controller) {
|
if (fieldType.module && fieldType.controller) {
|
||||||
var $controller = angular.injector(['ng', fieldType.module]).get('$controller');
|
var $controller = getInjector(fieldType.module).get('$controller');
|
||||||
$controller(fieldType.controller, {
|
$controller(fieldType.controller, {
|
||||||
'$scope' : scope,
|
'$scope' : scope,
|
||||||
'$element' : angular.element(fieldContainer.childNodes)
|
'$element' : angular.element(fieldContainer.childNodes)
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
<div class="guac-input-color"
|
<div class="guac-input-color"
|
||||||
ng-class="{
|
ng-class="{
|
||||||
'dark' : isDark(),
|
'dark' : isDark(),
|
||||||
'read-only' : colorPickerUnavailable
|
'read-only' : !isColorPickerAvailable()
|
||||||
}"
|
}"
|
||||||
|
ng-click="selectColor()"
|
||||||
ng-style="{
|
ng-style="{
|
||||||
'background-color' : model
|
'background-color' : model
|
||||||
}">
|
}">
|
||||||
|
Reference in New Issue
Block a user