| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082 |
- /* *
- *
- * Popup generator for Stock tools
- *
- * (c) 2009-2017 Sebastian Bochan
- *
- * License: www.highcharts.com/license
- *
- * */
- 'use strict';
- import H from '../parts/Globals.js';
- import U from '../parts/Utilities.js';
- var defined = U.defined,
- isArray = U.isArray,
- isObject = U.isObject,
- isString = U.isString,
- objectEach = U.objectEach,
- pick = U.pick,
- wrap = U.wrap;
- var addEvent = H.addEvent,
- createElement = H.createElement,
- indexFilter = /\d/g,
- PREFIX = 'highcharts-',
- DIV = 'div',
- INPUT = 'input',
- LABEL = 'label',
- BUTTON = 'button',
- SELECT = 'select',
- OPTION = 'option',
- SPAN = 'span',
- UL = 'ul',
- LI = 'li',
- H3 = 'h3';
- // onContainerMouseDown blocks internal popup events, due to e.preventDefault.
- // Related issue #4606
- wrap(H.Pointer.prototype, 'onContainerMouseDown', function (proceed, e) {
- var popupClass = e.target && e.target.className;
- // elements is not in popup
- if (!(isString(popupClass) &&
- popupClass.indexOf(PREFIX + 'popup-field') >= 0)
- ) {
- proceed.apply(this, Array.prototype.slice.call(arguments, 1));
- }
- });
- H.Popup = function (parentDiv, iconsURL) {
- this.init(parentDiv, iconsURL);
- };
- H.Popup.prototype = {
- /**
- * Initialize the popup. Create base div and add close button.
- * @private
- * @param {HTMLDOMElement} - container where popup should be placed
- * @param {Object} - user options
- * @return {HTMLDOMElement} - return created popup's div
- */
- init: function (parentDiv, iconsURL) {
- // create popup div
- this.container = createElement(DIV, {
- className: PREFIX + 'popup'
- }, null, parentDiv);
- this.lang = this.getLangpack();
- this.iconsURL = iconsURL;
- // add close button
- this.addCloseBtn();
- },
- /**
- * Create HTML element and attach click event (close popup).
- * @private
- */
- addCloseBtn: function () {
- var _self = this,
- closeBtn;
- // create close popup btn
- closeBtn = createElement(DIV, {
- className: PREFIX + 'popup-close'
- }, null, this.container);
- closeBtn.style['background-image'] = 'url(' +
- this.iconsURL + 'close.svg)';
- ['click', 'touchstart'].forEach(function (eventName) {
- addEvent(closeBtn, eventName, function () {
- _self.closePopup();
- });
- });
- },
- /**
- * Create two columns (divs) in HTML.
- * @private
- * @param {HTMLDOMElement} - container of columns
- * @return {Object} - reference to two HTML columns
- */
- addColsContainer: function (container) {
- var rhsCol,
- lhsCol;
- // left column
- lhsCol = createElement(DIV, {
- className: PREFIX + 'popup-lhs-col'
- }, null, container);
- // right column
- rhsCol = createElement(DIV, {
- className: PREFIX + 'popup-rhs-col'
- }, null, container);
- // wrapper content
- createElement(DIV, {
- className: PREFIX + 'popup-rhs-col-wrapper'
- }, null, rhsCol);
- return {
- lhsCol: lhsCol,
- rhsCol: rhsCol
- };
- },
- /**
- * Create input with label.
- * @private
- * @param {String} - chain of fields i.e params.styles.fontSize
- * @param {String} - indicator type
- * @param {HTMLDOMElement} - container where elements should be added
- * @param {String} - dafault value of input i.e period value is 14,
- * extracted from defaultOptions (ADD mode) or series options (EDIT mode)
- */
- addInput: function (option, type, parentDiv, value) {
- var optionParamList = option.split('.'),
- optionName = optionParamList[optionParamList.length - 1],
- lang = this.lang,
- inputName = PREFIX + type + '-' + optionName;
- if (!inputName.match(indexFilter)) {
- // add label
- createElement(
- LABEL, {
- innerHTML: lang[optionName] || optionName,
- htmlFor: inputName
- },
- null,
- parentDiv
- );
- }
- // add input
- createElement(
- INPUT,
- {
- name: inputName,
- value: value[0],
- type: value[1],
- className: PREFIX + 'popup-field'
- },
- null,
- parentDiv
- ).setAttribute(PREFIX + 'data-name', option);
- },
- /**
- * Create button.
- * @private
- * @param {HTMLDOMElement} - container where elements should be added
- * @param {String} - text placed as button label
- * @param {String} - add | edit | remove
- * @param {Function} - on click callback
- * @param {HTMLDOMElement} - container where inputs are generated
- * @return {HTMLDOMElement} - html button
- */
- addButton: function (parentDiv, label, type, callback, fieldsDiv) {
- var _self = this,
- closePopup = this.closePopup,
- getFields = this.getFields,
- button;
- button = createElement(BUTTON, {
- innerHTML: label
- }, null, parentDiv);
- ['click', 'touchstart'].forEach(function (eventName) {
- addEvent(button, eventName, function () {
- closePopup.call(_self);
- return callback(
- getFields(fieldsDiv, type)
- );
- });
- });
- return button;
- },
- /**
- * Get values from all inputs and create JSON.
- * @private
- * @param {HTMLDOMElement} - container where inputs are created
- * @param {String} - add | edit | remove
- * @return {Object} - fields
- */
- getFields: function (parentDiv, type) {
- var inputList = parentDiv.querySelectorAll('input'),
- optionSeries = '#' + PREFIX + 'select-series > option:checked',
- optionVolume = '#' + PREFIX + 'select-volume > option:checked',
- linkedTo = parentDiv.querySelectorAll(optionSeries)[0],
- volumeTo = parentDiv.querySelectorAll(optionVolume)[0],
- seriesId,
- param,
- fieldsOutput;
- fieldsOutput = {
- actionType: type,
- linkedTo: linkedTo && linkedTo.getAttribute('value'),
- fields: { }
- };
- [].forEach.call(inputList, function (input) {
- param = input.getAttribute(PREFIX + 'data-name');
- seriesId = input.getAttribute(PREFIX + 'data-series-id');
- // params
- if (seriesId) {
- fieldsOutput.seriesId = input.value;
- } else if (param) {
- fieldsOutput.fields[param] = input.value;
- } else {
- // type like sma / ema
- fieldsOutput.type = input.value;
- }
- });
- if (volumeTo) {
- fieldsOutput.fields['params.volumeSeriesID'] = volumeTo
- .getAttribute('value');
- }
- return fieldsOutput;
- },
- /**
- * Reset content of the current popup and show.
- * @private
- * @param {Chart} - chart
- * @param {Function} - on click callback
- * @return {Object} - fields
- */
- showPopup: function () {
- var popupDiv = this.container,
- toolbarClass = PREFIX + 'annotation-toolbar',
- popupCloseBtn = popupDiv
- .querySelectorAll('.' + PREFIX + 'popup-close')[0];
- // reset content
- popupDiv.innerHTML = '';
- // reset toolbar styles if exists
- if (popupDiv.className.indexOf(toolbarClass) >= 0) {
- popupDiv.classList.remove(toolbarClass);
- // reset toolbar inline styles
- popupDiv.removeAttribute('style');
- }
- // add close button
- popupDiv.appendChild(popupCloseBtn);
- popupDiv.style.display = 'block';
- },
- /**
- * Hide popup.
- * @private
- */
- closePopup: function () {
- this.popup.container.style.display = 'none';
- },
- /**
- * Create content and show popup.
- * @private
- * @param {String} - type of popup i.e indicators
- * @param {Chart} - chart
- * @param {Object} - options
- * @param {Function} - on click callback
- */
- showForm: function (type, chart, options, callback) {
- this.popup = chart.navigationBindings.popup;
- // show blank popup
- this.showPopup();
- // indicator form
- if (type === 'indicators') {
- this.indicators.addForm.call(this, chart, options, callback);
- }
- // annotation small toolbar
- if (type === 'annotation-toolbar') {
- this.annotations.addToolbar.call(this, chart, options, callback);
- }
- // annotation edit form
- if (type === 'annotation-edit') {
- this.annotations.addForm.call(this, chart, options, callback);
- }
- // flags form - add / edit
- if (type === 'flag') {
- this.annotations.addForm.call(this, chart, options, callback, true);
- }
- },
- /**
- * Return lang definitions for popup.
- * @private
- * @return {Object} - elements translations.
- */
- getLangpack: function () {
- return H.getOptions().lang.navigation.popup;
- },
- annotations: {
- /**
- * Create annotation simple form. It contains two buttons
- * (edit / remove) and text label.
- * @private
- * @param {Chart} - chart
- * @param {Object} - options
- * @param {Function} - on click callback
- */
- addToolbar: function (chart, options, callback) {
- var _self = this,
- lang = this.lang,
- popupDiv = this.popup.container,
- showForm = this.showForm,
- toolbarClass = PREFIX + 'annotation-toolbar',
- button;
- // set small size
- if (popupDiv.className.indexOf(toolbarClass) === -1) {
- popupDiv.className += ' ' + toolbarClass;
- }
- // set position
- popupDiv.style.top = chart.plotTop + 10 + 'px';
- // create label
- createElement(SPAN, {
- innerHTML: pick(
- // Advanced annotations:
- lang[options.langKey] || options.langKey,
- // Basic shapes:
- options.shapes && options.shapes[0].type
- )
- }, null, popupDiv);
- // add buttons
- button = this.addButton(
- popupDiv,
- lang.removeButton || 'remove',
- 'remove',
- callback,
- popupDiv
- );
- button.className += ' ' + PREFIX + 'annotation-remove-button';
- button.style['background-image'] = 'url(' +
- this.iconsURL + 'destroy.svg)';
- button = this.addButton(
- popupDiv,
- lang.editButton || 'edit',
- 'edit',
- function () {
- showForm.call(
- _self,
- 'annotation-edit',
- chart,
- options,
- callback
- );
- },
- popupDiv
- );
- button.className += ' ' + PREFIX + 'annotation-edit-button';
- button.style['background-image'] = 'url(' +
- this.iconsURL + 'edit.svg)';
- },
- /**
- * Create annotation simple form.
- * It contains fields with param names.
- * @private
- * @param {Chart} - chart
- * @param {Object} - options
- * @param {Function} - on click callback
- * @param {Boolean} - if it is a form declared for init annotation
- */
- addForm: function (chart, options, callback, isInit) {
- var popupDiv = this.popup.container,
- lang = this.lang,
- bottomRow,
- lhsCol;
- // create title of annotations
- lhsCol = createElement('h2', {
- innerHTML: lang[options.langKey] || options.langKey,
- className: PREFIX + 'popup-main-title'
- }, null, popupDiv);
- // left column
- lhsCol = createElement(DIV, {
- className: PREFIX + 'popup-lhs-col ' + PREFIX + 'popup-lhs-full'
- }, null, popupDiv);
- bottomRow = createElement(DIV, {
- className: PREFIX + 'popup-bottom-row'
- }, null, popupDiv);
- this.annotations.addFormFields.call(
- this,
- lhsCol,
- chart,
- '',
- options,
- [],
- true
- );
- this.addButton(
- bottomRow,
- isInit ?
- (lang.addButton || 'add') :
- (lang.saveButton || 'save'),
- isInit ? 'add' : 'save',
- callback,
- popupDiv
- );
- },
- /**
- * Create annotation's form fields.
- * @private
- * @param {HTMLDOMElement} - div where inputs are placed
- * @param {Chart} - chart
- * @param {String} - name of parent to create chain of names
- * @param {Object} - options
- * @param {Array} - storage - array where all items are stored
- * @param {Boolean} - isRoot - recursive flag for root
- */
- addFormFields: function (
- parentDiv,
- chart,
- parentNode,
- options,
- storage,
- isRoot
- ) {
- var _self = this,
- addFormFields = this.annotations.addFormFields,
- addInput = this.addInput,
- lang = this.lang,
- parentFullName,
- titleName;
- objectEach(options, function (value, option) {
- // create name like params.styles.fontSize
- parentFullName = parentNode !== '' ?
- parentNode + '.' + option : option;
- if (isObject(value)) {
- if (
- // value is object of options
- !isArray(value) ||
- // array of objects with params. i.e labels in Fibonacci
- (isArray(value) && isObject(value[0]))
- ) {
- titleName = lang[option] || option;
- if (!titleName.match(indexFilter)) {
- storage.push([
- true,
- titleName,
- parentDiv
- ]);
- }
- addFormFields.call(
- _self,
- parentDiv,
- chart,
- parentFullName,
- value,
- storage,
- false
- );
- } else {
- storage.push([
- _self,
- parentFullName,
- 'annotation',
- parentDiv,
- value
- ]);
- }
- }
- });
- if (isRoot) {
- storage = storage.sort(function (a) {
- return a[1].match(/format/g) ? -1 : 1;
- });
- storage.forEach(function (genInput) {
- if (genInput[0] === true) {
- createElement(SPAN, {
- className: PREFIX + 'annotation-title',
- innerHTML: genInput[1]
- }, null, genInput[2]);
- } else {
- addInput.apply(genInput[0], genInput.splice(1));
- }
- });
- }
- }
- },
- indicators: {
- /**
- * Create indicator's form. It contains two tabs (ADD and EDIT) with
- * content.
- * @private
- * @param {Chart} - chart
- * @param {Object} - options
- * @param {Function} - on click callback
- */
- addForm: function (chart, options, callback) {
- var tabsContainers,
- indicators = this.indicators,
- lang = this.lang,
- buttonParentDiv;
- // add tabs
- this.tabs.init.call(this, chart);
- // get all tabs content divs
- tabsContainers = this.popup.container
- .querySelectorAll('.' + PREFIX + 'tab-item-content');
- // ADD tab
- this.addColsContainer(tabsContainers[0]);
- indicators.addIndicatorList.call(
- this,
- chart,
- tabsContainers[0],
- 'add'
- );
- buttonParentDiv = tabsContainers[0]
- .querySelectorAll('.' + PREFIX + 'popup-rhs-col')[0];
- this.addButton(
- buttonParentDiv,
- lang.addButton || 'add',
- 'add',
- callback,
- buttonParentDiv
- );
- // EDIT tab
- this.addColsContainer(tabsContainers[1]);
- indicators.addIndicatorList.call(
- this,
- chart,
- tabsContainers[1],
- 'edit'
- );
- buttonParentDiv = tabsContainers[1]
- .querySelectorAll('.' + PREFIX + 'popup-rhs-col')[0];
- this.addButton(
- buttonParentDiv,
- lang.saveButton || 'save',
- 'edit',
- callback,
- buttonParentDiv
- );
- this.addButton(
- buttonParentDiv,
- lang.removeButton || 'remove',
- 'remove',
- callback,
- buttonParentDiv
- );
- },
- /**
- * Create HTML list of all indicators (ADD mode) or added indicators
- * (EDIT mode).
- * @private
- * @param {Chart} - chart
- * @param {HTMLDOMElement} - container where list is added
- * @param {String} - 'edit' or 'add' mode
- */
- addIndicatorList: function (chart, parentDiv, listType) {
- var _self = this,
- lhsCol = parentDiv
- .querySelectorAll('.' + PREFIX + 'popup-lhs-col')[0],
- rhsCol = parentDiv
- .querySelectorAll('.' + PREFIX + 'popup-rhs-col')[0],
- isEdit = listType === 'edit',
- series = isEdit ? chart.series : // EDIT mode
- chart.options.plotOptions, // ADD mode
- addFormFields = this.indicators.addFormFields,
- rhsColWrapper,
- indicatorList,
- item;
- // create wrapper for list
- indicatorList = createElement(UL, {
- className: PREFIX + 'indicator-list'
- }, null, lhsCol);
- rhsColWrapper = rhsCol
- .querySelectorAll('.' + PREFIX + 'popup-rhs-col-wrapper')[0];
- objectEach(series, function (serie, value) {
- var seriesOptions = serie.options;
- if (
- serie.params ||
- seriesOptions && seriesOptions.params
- ) {
- var indicatorNameType = _self.indicators
- .getNameType(serie, value),
- indicatorType = indicatorNameType.type;
- item = createElement(LI, {
- className: PREFIX + 'indicator-list',
- innerHTML: indicatorNameType.name
- }, null, indicatorList);
- ['click', 'touchstart'].forEach(function (eventName) {
- addEvent(item, eventName, function () {
- addFormFields.call(
- _self,
- chart,
- isEdit ? serie : series[indicatorType],
- indicatorNameType.type,
- rhsColWrapper
- );
- // add hidden input with series.id
- if (isEdit && serie.options) {
- createElement(INPUT, {
- type: 'hidden',
- name: PREFIX + 'id-' + indicatorType,
- value: serie.options.id
- }, null, rhsColWrapper)
- .setAttribute(
- PREFIX + 'data-series-id',
- serie.options.id
- );
- }
- });
- });
- }
- });
- // select first item from the list
- if (indicatorList.childNodes.length > 0) {
- indicatorList.childNodes[0].click();
- }
- },
- /**
- * Extract full name and type of requested indicator.
- * @private
- * @param {Series} - series which name is needed.
- * (EDIT mode - defaultOptions.series, ADD mode - indicator series).
- * @param {String} - indicator type like: sma, ema, etc.
- * @return {Object} - series name and type like: sma, ema, etc.
- */
- getNameType: function (series, type) {
- var options = series.options,
- seriesTypes = H.seriesTypes,
- // add mode
- seriesName = seriesTypes[type] &&
- seriesTypes[type].prototype.nameBase || type.toUpperCase(),
- seriesType = type;
- // edit
- if (options && options.type) {
- seriesType = series.options.type;
- seriesName = series.name;
- }
- return {
- name: seriesName,
- type: seriesType
- };
- },
- /**
- * List all series with unique ID. Its mandatory for indicators to set
- * correct linking.
- * @private
- * @param {String} - indicator type like: sma, ema, etc.
- * @param {String} - type of select i.e series or volume.
- * @param {Chart} - chart
- * @param {HTMLDOMElement} - element where created HTML list is added
- * @param {String} selectedOption
- * optional param for default value in dropdown
- */
- listAllSeries: function (
- type,
- optionName,
- chart,
- parentDiv,
- selectedOption
- ) {
- var selectName = PREFIX + optionName + '-type-' + type,
- lang = this.lang,
- selectBox,
- seriesOptions;
- createElement(
- LABEL, {
- innerHTML: lang[optionName] || optionName,
- htmlFor: selectName
- },
- null,
- parentDiv
- );
- // select type
- selectBox = createElement(
- SELECT,
- {
- name: selectName,
- className: PREFIX + 'popup-field'
- },
- null,
- parentDiv
- );
- selectBox.setAttribute('id', PREFIX + 'select-' + optionName);
- // list all series which have id - mandatory for creating indicator
- chart.series.forEach(function (serie) {
- seriesOptions = serie.options;
- if (
- !seriesOptions.params &&
- seriesOptions.id &&
- seriesOptions.id !== PREFIX + 'navigator-series'
- ) {
- createElement(
- OPTION,
- {
- innerHTML: seriesOptions.name || seriesOptions.id,
- value: seriesOptions.id
- },
- null,
- selectBox
- );
- }
- });
- if (defined(selectedOption)) {
- selectBox.value = selectedOption;
- }
- },
- /**
- * Create typical inputs for chosen indicator. Fields are extracted from
- * defaultOptions (ADD mode) or current indicator (ADD mode). Two extra
- * fields are added:
- * - hidden input - contains indicator type (required for callback)
- * - select - list of series which can be linked with indicator
- * @private
- * @param {Chart} - chart
- * @param {Series} - indicator
- * @param {String} - indicator type like: sma, ema, etc.
- * @param {HTMLDOMElement} - element where created HTML list is added
- */
- addFormFields: function (chart, series, seriesType, rhsColWrapper) {
- var fields = series.params || series.options.params,
- getNameType = this.indicators.getNameType;
- // reset current content
- rhsColWrapper.innerHTML = '';
- // create title (indicator name in the right column)
- createElement(
- H3,
- {
- className: PREFIX + 'indicator-title',
- innerHTML: getNameType(series, seriesType).name
- },
- null,
- rhsColWrapper
- );
- // input type
- createElement(
- INPUT,
- {
- type: 'hidden',
- name: PREFIX + 'type-' + seriesType,
- value: seriesType
- },
- null,
- rhsColWrapper
- );
- // list all series with id
- this.indicators.listAllSeries.call(
- this,
- seriesType,
- 'series',
- chart,
- rhsColWrapper,
- series.linkedParent && fields.volumeSeriesID
- );
- if (fields.volumeSeriesID) {
- this.indicators.listAllSeries.call(
- this,
- seriesType,
- 'volume',
- chart,
- rhsColWrapper,
- series.linkedParent && series.linkedParent.options.id
- );
- }
- // add param fields
- this.indicators.addParamInputs.call(
- this,
- chart,
- 'params',
- fields,
- seriesType,
- rhsColWrapper
- );
- },
- /**
- * Recurent function which lists all fields, from params object and
- * create them as inputs. Each input has unique `data-name` attribute,
- * which keeps chain of fields i.e params.styles.fontSize.
- * @private
- * @param {Chart} - chart
- * @param {String} - name of parent to create chain of names
- * @param {Series} - fields - params which are based for input create
- * @param {String} - indicator type like: sma, ema, etc.
- * @param {HTMLDOMElement} - element where created HTML list is added
- */
- addParamInputs: function (chart, parentNode, fields, type, parentDiv) {
- var _self = this,
- addParamInputs = this.indicators.addParamInputs,
- addInput = this.addInput,
- parentFullName;
- objectEach(fields, function (value, fieldName) {
- // create name like params.styles.fontSize
- parentFullName = parentNode + '.' + fieldName;
- if (isObject(value)) {
- addParamInputs.call(
- _self,
- chart,
- parentFullName,
- value,
- type,
- parentDiv
- );
- } else if (
- // skip volume field which is created by addFormFields
- parentFullName !== 'params.volumeSeriesID'
- ) {
- addInput.call(
- _self,
- parentFullName,
- type,
- parentDiv,
- [value, 'text'] // all inputs are text type
- );
- }
- });
- },
- /**
- * Get amount of indicators added to chart.
- * @private
- * @return {Number} - Amount of indicators
- */
- getAmount: function () {
- var series = this.series,
- counter = 0;
- objectEach(series, function (serie) {
- var seriesOptions = serie.options;
- if (
- serie.params ||
- seriesOptions && seriesOptions.params
- ) {
- counter++;
- }
- });
- return counter;
- }
- },
- tabs: {
- /**
- * Init tabs. Create tab menu items, tabs containers
- * @private
- * @param {Chart} - reference to current chart
- */
- init: function (chart) {
- var tabs = this.tabs,
- indicatorsCount = this.indicators.getAmount.call(chart),
- firstTab; // run by default
- // create menu items
- firstTab = tabs.addMenuItem.call(this, 'add');
- tabs.addMenuItem.call(this, 'edit', indicatorsCount);
- // create tabs containers
- tabs.addContentItem.call(this, 'add');
- tabs.addContentItem.call(this, 'edit');
- tabs.switchTabs.call(this, indicatorsCount);
- // activate first tab
- tabs.selectTab.call(this, firstTab, 0);
- },
- /**
- * Create tab menu item
- * @private
- * @param {String} - `add` or `edit`
- * @param {Number} - Disable tab when 0
- * @return {HTMLDOMElement} - created HTML tab-menu element
- */
- addMenuItem: function (tabName, disableTab) {
- var popupDiv = this.popup.container,
- className = PREFIX + 'tab-item',
- lang = this.lang,
- menuItem;
- if (disableTab === 0) {
- className += ' ' + PREFIX + 'tab-disabled';
- }
- // tab 1
- menuItem = createElement(
- SPAN,
- {
- innerHTML: lang[tabName + 'Button'] || tabName,
- className: className
- },
- null,
- popupDiv
- );
- menuItem.setAttribute(PREFIX + 'data-tab-type', tabName);
- return menuItem;
- },
- /**
- * Create tab content
- * @private
- * @return {HTMLDOMElement} - created HTML tab-content element
- */
- addContentItem: function () {
- var popupDiv = this.popup.container;
- return createElement(
- DIV,
- {
- className: PREFIX + 'tab-item-content'
- },
- null,
- popupDiv
- );
- },
- /**
- * Add click event to each tab
- * @private
- * @param {Number} - Disable tab when 0
- */
- switchTabs: function (disableTab) {
- var _self = this,
- popupDiv = this.popup.container,
- tabs = popupDiv.querySelectorAll('.' + PREFIX + 'tab-item'),
- dataParam;
- tabs.forEach(function (tab, i) {
- dataParam = tab.getAttribute(PREFIX + 'data-tab-type');
- if (dataParam === 'edit' && disableTab === 0) {
- return;
- }
- ['click', 'touchstart'].forEach(function (eventName) {
- addEvent(tab, eventName, function () {
- // reset class on other elements
- _self.tabs.deselectAll.call(_self);
- _self.tabs.selectTab.call(_self, this, i);
- });
- });
- });
- },
- /**
- * Set tab as visible
- * @private
- * @param {HTMLDOMElement} - current tab
- * @param {Number} - Index of tab in menu
- */
- selectTab: function (tab, index) {
- var allTabs = this.popup.container
- .querySelectorAll('.' + PREFIX + 'tab-item-content');
- tab.className += ' ' + PREFIX + 'tab-item-active';
- allTabs[index].className += ' ' + PREFIX + 'tab-item-show';
- },
- /**
- * Set all tabs as invisible.
- * @private
- */
- deselectAll: function () {
- var popupDiv = this.popup.container,
- tabs = popupDiv
- .querySelectorAll('.' + PREFIX + 'tab-item'),
- tabsContent = popupDiv
- .querySelectorAll('.' + PREFIX + 'tab-item-content'),
- i;
- for (i = 0; i < tabs.length; i++) {
- tabs[i].classList.remove(PREFIX + 'tab-item-active');
- tabsContent[i].classList.remove(PREFIX + 'tab-item-show');
- }
- }
- }
- };
- addEvent(H.NavigationBindings, 'showPopup', function (config) {
- if (!this.popup) {
- // Add popup to main container
- this.popup = new H.Popup(
- this.chart.container, (
- this.chart.options.navigation.iconsURL ||
- (
- this.chart.options.stockTools &&
- this.chart.options.stockTools.gui.iconsURL
- ) ||
- 'https://code.highcharts.com/8.0.0/gfx/stock-icons/'
- )
- );
- }
- this.popup.showForm(
- config.formType,
- this.chart,
- config.options,
- config.onSubmit
- );
- });
- addEvent(H.NavigationBindings, 'closePopup', function () {
- if (this.popup) {
- this.popup.closePopup();
- }
- });
|