import * as ko from "knockout" ; import * as Survey from "survey-knockout" ; import { IAction } from "survey-knockout" ; import { CreatorBase } from "./creator-base" ; import { editorLocalization } from "./editorLocalization" ; /**
 * The Toolbox item description.
 */ export interface IQuestionToolboxItem extends IAction { /**
     * A unique name
     */ name : string ; /**
     * Icon name
     */ iconName : string ; /**
     * The JSON that used to create a new question/panel. The 'type' attribute is required.
     */ json : any ; /**
     * Toolbox item title
     */ title : string ; /**
     * Toolbox item tooltip. It equals to title if it is empty
     */ tooltip ? : string ; /**
     * True, if an end user added this item into Toolbox from the survey.
     */ isCopied : boolean ; /**
     * Toolbox item category. If it is empty, it goes to 'General' category.
     */ category : string ; } /**
 * The list of Toolbox items.
 */ export class QuestionToolbox { private _orderedQuestions = [ "text" , "checkbox" , "radiogroup" , "dropdown" , "comment" , "rating" , "ranking" , "imagepicker" , "boolean" , "image" , "html" , "signaturepad" , ] ; private _questionDefaultSettings = { imagepicker : ( ) => { return { choices : [ { value : "lion" , imageLink : "https://surveyjs.io/Content/Images/examples/image-picker/lion.jpg" , } , { value : "giraffe" , imageLink : "https://surveyjs.io/Content/Images/examples/image-picker/giraffe.jpg" , } , { value : "panda" , imageLink : "https://surveyjs.io/Content/Images/examples/image-picker/panda.jpg" , } , { value : "camel" , imageLink : "https://surveyjs.io/Content/Images/examples/image-picker/camel.jpg" , } , ] , } ; } , image : ( ) => { return { imageLink : "https://surveyjs.io/Content/Images/examples/image-picker/lion.jpg" , } ; } , } ; /**
     * Modify this array to change the toolbox items order.
     */ public get orderedQuestions ( ) { return this . _orderedQuestions ; } public set orderedQuestions ( questions ) { this . _orderedQuestions = questions ; this . reorderItems ( ) ; } /**
     * The maximum number of copied toolbox items. If an user adding copiedItemMaxCount + 1 item, the first added item will be removed.
     */ public copiedItemMaxCount : number = 3 ; private allowExpandMultipleCategoriesValue : boolean = false ; private keepAllCategoriesExpandedValue : boolean = false ; private itemsValue : Array < IQuestionToolboxItem > = [ ] ; koItems = ko . observableArray ( ) ; koCategories = ko . observableArray ( ) ; koActiveCategory = ko . observable ( "" ) ; koHasCategories = ko . observable ( false ) ; koCanCollapseCategories = ko . observable ( true ) ; constructor ( supportedQuestions = null , public creator = null ) { this . createDefaultItems ( supportedQuestions ) ; var self = this ; this . koActiveCategory . subscribe ( function ( newValue ) { for ( var i = 0 ; i < self . koCategories ( ) . length ; i ++ ) { var category = self . koCategories ( ) [ i ] ; ( < any > category ) . koCollapsed ( ( < any > category ) . name !== newValue ) ; } } ) ; } /**
     * The Array of Toolbox items as Text JSON.
     */ public get jsonText ( ) { return JSON . stringify ( this . itemsValue ) ; } public set jsonText ( value ) { this . itemsValue = value ? JSON . parse ( value ) : [ ] ; this . onItemsChanged ( ) ; } /**
     * The Array of copied Toolbox items as Text JSON.
     */ public get copiedJsonText ( ) : string { return JSON . stringify ( this . copiedItems ) ; } public set copiedJsonText ( value ) { var newItems = value ? JSON . parse ( value ) : [ ] ; this . clearCopiedItems ( ) ; for ( let i = 0 ; i < newItems . length ; i ++ ) { newItems [ i ] . isCopied = true ; this . addItem ( newItems [ i ] ) ; } } /**
     * The Array of Toolbox items.
     */ public get items ( ) : Array < IQuestionToolboxItem > { return this . itemsValue ; } public get itemNames ( ) : Array < string > { const res = [ ] ; for ( let i = 0 ; i < this . items . length ; i ++ ) { res . push ( this . items [ i ] . name ) ; } return res ; } /**
     * The Array of copied Toolbox items
     */ public get copiedItems ( ) : Array < IQuestionToolboxItem > { const result = [ ] ; for ( let i = 0 ; i < this . itemsValue . length ; i ++ ) { if ( this . itemsValue [ i ] . isCopied ) result . push ( this . itemsValue [ i ] ) ; } return result ; } param items param clearAll public addItems ( items , clearAll = false ) { if ( clearAll ) { this . clearItems ( ) ; } for ( let i = 0 ; i < items . length ; i ++ ) { this . itemsValue . push ( items [ i ] ) ; } this . onItemsChanged ( ) ; } param question param options public addCopiedItem ( question , options = null ) { if ( ! options ) options = { } ; const name = ! ! options . name ? options . name : question . name ; const title = ! ! options . title ? options . title : name ; const tooltip = ! ! options . tooltip ? options . tooltip : title ; const item = { id : name , name : name , title : title , tooltip : tooltip , isCopied : options . isCopied !== false , iconName : ! ! options . iconName ? options . iconName : "icon-default" , json : ! ! options . json ? options . json : this . getQuestionJSON ( question ) , category : ! ! options . category ? options . category : "" , } ; if ( this . replaceItem ( item ) ) return ; const copied = this . copiedItems ; if ( this . copiedItemMaxCount > 0 && copied . length == this . copiedItemMaxCount ) this . removeItem ( copied [ this . copiedItemMaxCount - 1 ] . name ) ; this . addItem ( item ) ; } param item param index see IQuestionToolboxItem public addItem ( item , index ? ) { this . correctItem ( item ) ; if ( index === undefined ) { this . itemsValue . push ( item ) ; } else { this . itemsValue . splice ( index , 0 , item ) ; } this . onItemsChanged ( ) ; } private correctItem ( item ) { if ( ! item . title ) item . title = item . name ; if ( ! item . tooltip ) item . tooltip = item . title ; } param item see IQuestionToolboxItem public replaceItem ( item ) { this . correctItem ( item ) ; const index = this . indexOf ( item . name ) ; if ( index < 0 ) return ; this . itemsValue [ index ] = item ; this . onItemsChanged ( ) ; return true ; } param name see IQuestionToolboxItem public removeItem ( name ) { const index = this . indexOf ( name ) ; if ( index < 0 ) return false ; this . itemsValue . splice ( index , 1 ) ; this . onItemsChanged ( ) ; return true ; } /**
     * Remove all toolbox items.
     */ public clearItems ( ) { this . itemsValue = [ ] ; this . onItemsChanged ( ) ; } /**
     * Remove all copied toolbox items.
     */ public clearCopiedItems ( ) { const removedItems = this . copiedItems ; for ( let i = 0 ; i < removedItems . length ; i ++ ) { this . removeItem ( removedItems [ i ] . name ) ; } } param name public getItemByName ( name ) { const index = this . indexOf ( name ) ; return index > - 1 ? this . itemsValue [ index ] : null ; } see activeCategory public get allowExpandMultipleCategories ( ) : boolean { return this . allowExpandMultipleCategoriesValue ; } public set allowExpandMultipleCategories ( val ) { this . allowExpandMultipleCategoriesValue = val ; this . updateCategoriesState ( ) ; } /**
     * Set it to true to expand all categories and hide expand/collapse category buttons
     */ public get keepAllCategoriesExpanded ( ) : boolean { return this . keepAllCategoriesExpandedValue ; } public set keepAllCategoriesExpanded ( val ) { this . keepAllCategoriesExpandedValue = val ; this . koCanCollapseCategories ( ! this . keepAllCategoriesExpanded ) ; this . updateCategoriesState ( ) ; } private updateCategoriesState ( ) { var noActive = this . allowExpandMultipleCategories || this . keepAllCategoriesExpanded ; if ( noActive ) { this . activeCategory = "" ; if ( this . keepAllCategoriesExpanded ) { this . expandAllCategories ( ) ; } } else { if ( this . koCategories ( ) . length > 0 ) { this . activeCategory = ( < any > this . koCategories ( ) [ 0 ] ) . name ; } } } param name param category public changeCategory ( name , category ) { this . changeCategories ( [ { name : name , category : category } ] ) ; } param changedItems public changeCategories ( changedItems ) { for ( var i = 0 ; i < changedItems . length ; i ++ ) { var item = changedItems [ i ] ; var toolboxItem = this . getItemByName ( item . name ) ; if ( toolboxItem ) { toolboxItem . category = item . category ; } } this . onItemsChanged ( ) ; } see allowExpandMultipleCategories see expandCategory see collapseCategory public get activeCategory ( ) : string { return this . koActiveCategory ( ) ; } public set activeCategory ( val ) { this . koActiveCategory ( val ) ; } private doCategoryClick ( categoryName ) { if ( this . keepAllCategoriesExpanded ) return ; if ( this . allowExpandMultipleCategories ) { var category = this . getCategoryByName ( categoryName ) ; if ( category ) { category . koCollapsed ( ! category . koCollapsed ( ) ) ; } } else { this . activeCategory = categoryName ; } } param categoryName see allowExpandMultipleCategories see collapseCategory public expandCategory ( categoryName ) { if ( this . allowExpandMultipleCategories ) { var category = this . getCategoryByName ( categoryName ) ; if ( category ) { category . koCollapsed ( false ) ; } } else { this . activeCategory = categoryName ; } } param categoryName see allowExpandMultipleCategories public collapseCategory ( categoryName ) { if ( ! this . allowExpandMultipleCategories ) return ; var category = this . getCategoryByName ( categoryName ) ; if ( category ) { category . koCollapsed ( true ) ; } } see allowExpandMultipleCategories public expandAllCategories ( ) { this . expandCollapseAllCategories ( false ) ; } see allowExpandMultipleCategories public collapseAllCategories ( ) { this . expandCollapseAllCategories ( true ) ; } private expandCollapseAllCategories ( isCollapsed ) { var categories = this . koCategories ( ) ; for ( var i = 0 ; i < categories . length ; i ++ ) { ( < any > categories [ i ] ) . koCollapsed ( isCollapsed ) ; } } private getCategoryByName ( categoryName ) { var categories = this . koCategories ( ) ; for ( var i = 0 ; i < categories . length ; i ++ ) { var category = < any > categories [ i ] ; if ( category . name === categoryName ) return category ; } return null ; } protected onItemsChanged ( ) { this . koItems ( [ ] ) ; this . koItems ( this . itemsValue ) ; var categories = [ ] ; var categoriesHash = { } ; var prevActiveCategory = this . koActiveCategory ( ) ; var self = this ; for ( var i = 0 ; i < this . itemsValue . length ; i ++ ) { var item = this . itemsValue [ i ] ; var categoryName = item . category ? item . category : editorLocalization . getString ( "ed.toolboxGeneralCategory" ) ; if ( ! categoriesHash [ categoryName ] ) { var category = { name : categoryName , items : [ ] , koCollapsed : ko . observable ( categoryName !== prevActiveCategory && ! this . keepAllCategoriesExpanded ) , expand : function ( ) { self . doCategoryClick ( this . name ) ; } , } ; categoriesHash [ categoryName ] = category ; categories . push ( category ) ; } categoriesHash [ categoryName ] . items . push ( item ) ; } this . koCategories ( categories ) ; if ( ! this . keepAllCategoriesExpanded ) { if ( ! this . allowExpandMultipleCategories ) { if ( prevActiveCategory && categoriesHash [ prevActiveCategory ] ) { this . koActiveCategory ( prevActiveCategory ) ; } else { this . koActiveCategory ( categories . length > 0 ? categories [ 0 ] . name : "" ) ; } } else { if ( categories . length > 0 ) { categories [ 0 ] . koCollapsed ( false ) ; } } } this . koHasCategories ( categories . length > 1 ) ; } private indexOf ( name ) { for ( var i = 0 ; i < this . itemsValue . length ; i ++ ) { if ( this . itemsValue [ i ] . name == name ) return i ; } return - 1 ; } private reorderItems ( ) { this . itemsValue . sort ( ( i1 , i2 ) => { var index1 = this . _orderedQuestions . indexOf ( i1 . name ) ; if ( index1 === - 1 ) index1 = Number . MAX_VALUE ; var index2 = this . _orderedQuestions . indexOf ( i2 . name ) ; if ( index2 === - 1 ) index2 = Number . MAX_VALUE ; return index1 - index2 ; } ) ; this . onItemsChanged ( ) ; } private createDefaultItems ( supportedQuestions ) { this . clearItems ( ) ; var questions = this . getQuestionTypes ( supportedQuestions ) ; for ( var i = 0 ; i < questions . length ; i ++ ) { var name = questions [ i ] ; var question = Survey . ElementFactory . Instance . createElement ( name , "q1" ) ; if ( ! question ) { question = Survey . Serializer . createClass ( name ) ; } var json = this . getQuestionJSON ( question ) ; var title = editorLocalization . getString ( "qt." + name ) ; const item = { id : name , name : name , iconName : "icon-" + name , title : title , tooltip : title , json : json , isCopied : false , category : "" , } ; this . itemsValue . push ( item ) ; } this . registerCustomWidgets ( ) ; this . registerComponentQuestions ( ) ; this . onItemsChanged ( ) ; } private registerCustomWidgets ( ) { var inst = Survey . CustomWidgetCollection . Instance ; if ( ! inst . getActivatedBy ) return ; var widgets = inst . widgets ; for ( var i = 0 ; i < widgets . length ; i ++ ) { if ( inst . getActivatedBy ( widgets [ i ] . name ) != "customtype" ) continue ; var widgetJson = widgets [ i ] . widgetJson ; if ( ! widgetJson . widgetIsLoaded || ! widgetJson . widgetIsLoaded ( ) ) continue ; this . addItemFromJSON ( widgetJson ) ; } } private registerComponentQuestions ( ) { var items = this . getComponentItems ( ) ; for ( var i = 0 ; i < items . length ; i ++ ) { this . addItemFromJSON ( items [ i ] . json ) ; } } private getComponentItems ( ) { var instanceOwner = Survey [ "CustomQuestionCollection" ] ; if ( ! instanceOwner ) { instanceOwner = Survey [ "ComponentCollection" ] ; } if ( ! instanceOwner ) return [ ] ; var items = instanceOwner . Instance [ "items" ] ; return ! ! items ? items : [ ] ; } private addItemFromJSON ( json ) { if ( json . showInToolbox === false ) return ; const iconName = json . iconName ? json . iconName : "icon-default" ; let title = editorLocalization . getString ( "qt." + json . name ) ; if ( ! title || title == json . name ) { title = json . title ; } if ( ! title ) { title = json . name ; } var elementJson = json . defaultJSON ? json . defaultJSON : { } ; if ( ! elementJson . type ) { elementJson . type = json . name ; } var category = json . category ? json . category : "" ; const item = { id : json . name , name : json . name , iconName : iconName , title : title , tooltip : title , json : elementJson , isCopied : false , category : category , } ; this . itemsValue . push ( item ) ; } private getQuestionJSON ( question ) { var json = new Survey . JsonObject ( ) . toJsonObject ( question ) ; json . type = question . getType ( ) ; if ( ! ! this . _questionDefaultSettings [ json . type ] ) { var defaultSettings = this . _questionDefaultSettings [ json . type ] ( ) ; for ( var key in defaultSettings ) { json [ key ] = defaultSettings [ key ] ; } } return json ; } private getQuestionTypes ( supportedQuestions ) { const allTypes = Survey . ElementFactory . Instance . getAllTypes ( ) ; if ( ! supportedQuestions || supportedQuestions . length == 0 ) supportedQuestions = allTypes ; const questions = [ ] ; for ( let i = 0 ; i < this . orderedQuestions . length ; i ++ ) { const name = this . orderedQuestions [ i ] ; if ( supportedQuestions . indexOf ( name ) > - 1 && allTypes . indexOf ( name ) > - 1 ) questions . push ( name ) ; } for ( let i = 0 ; i < supportedQuestions . length ; i ++ ) { const name = supportedQuestions [ i ] ; if ( questions . indexOf ( supportedQuestions [ i ] ) < 0 && allTypes . indexOf ( name ) > - 1 ) questions . push ( name ) ; } return questions ; } public dispose ( ) { } }