├── .editorconfig ├── .gitignore ├── .verb.md ├── CHANGELOG.yml ├── Chapters-Source ├── part-01 │ ├── 03-HelloWorld │ │ ├── .gitignore │ │ ├── README.md │ │ ├── build │ │ │ ├── ExtTut-01-HelloWorld_dev.zip │ │ │ └── ExtTut-03-HelloWorld_dev.zip │ │ ├── grunt │ │ │ ├── Gruntfile.clean.js │ │ │ ├── Gruntfile.cleanempty.js │ │ │ ├── Gruntfile.compress.js │ │ │ ├── Gruntfile.copy.js │ │ │ ├── Gruntfile.js │ │ │ ├── Gruntfile.replace.js │ │ │ ├── Gruntfile.uglify.js │ │ │ ├── grunt-config.yml │ │ │ ├── gruntReplacements.yml │ │ │ ├── gruntReplacements_dev.yml │ │ │ ├── gruntReplacements_release.yml │ │ │ └── package.json │ │ └── src │ │ │ ├── exttut-03-helloworld.js │ │ │ └── exttut-03-helloworld.qext │ ├── 04-Debugging │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── .yo-rc.json │ │ ├── README.md │ │ ├── grunt │ │ │ ├── .jshintrc-dev │ │ │ ├── .jshintrc-release │ │ │ ├── Gruntfile.clean.js │ │ │ ├── Gruntfile.cleanempty.js │ │ │ ├── Gruntfile.compress.js │ │ │ ├── Gruntfile.copy.js │ │ │ ├── Gruntfile.js │ │ │ ├── Gruntfile.jshint.js │ │ │ ├── Gruntfile.projectconfig.js │ │ │ ├── Gruntfile.replace.js │ │ │ ├── Gruntfile.uglify.js │ │ │ ├── grunt-config.yml │ │ │ ├── gruntReplacements.yml │ │ │ ├── gruntReplacements_dev.yml │ │ │ ├── gruntReplacements_release.yml │ │ │ └── package.json │ │ └── src │ │ │ ├── .jshintrc │ │ │ ├── exttut-04-debugging.js │ │ │ ├── exttut-04-debugging.png │ │ │ └── exttut-04-debugging.qext │ ├── 05-Improving-HelloWorld │ │ ├── .gitignore │ │ ├── .yo-rc.json │ │ ├── README.md │ │ ├── build │ │ │ └── ExtTut-05-Improving-HelloWorld_dev.zip │ │ ├── grunt │ │ │ ├── Gruntfile.clean.js │ │ │ ├── Gruntfile.cleanempty.js │ │ │ ├── Gruntfile.compress.js │ │ │ ├── Gruntfile.copy.js │ │ │ ├── Gruntfile.js │ │ │ ├── Gruntfile.replace.js │ │ │ ├── Gruntfile.uglify.js │ │ │ ├── grunt-config.yml │ │ │ ├── gruntReplacements.yml │ │ │ ├── gruntReplacements_dev.yml │ │ │ ├── gruntReplacements_release.yml │ │ │ └── package.json │ │ └── src │ │ │ ├── ImprovedHelloWorld.png │ │ │ ├── exttut-05-improving-helloworld.js │ │ │ └── exttut-05-improving-helloworld.qext │ ├── 06-Using-Properties-Basic │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── .yo-rc.json │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── grunt │ │ │ ├── .jshintrc-dev │ │ │ ├── .jshintrc-release │ │ │ ├── Gruntfile.clean.js │ │ │ ├── Gruntfile.cleanempty.js │ │ │ ├── Gruntfile.compress.js │ │ │ ├── Gruntfile.copy.js │ │ │ ├── Gruntfile.js │ │ │ ├── Gruntfile.jshint.js │ │ │ ├── Gruntfile.projectconfig.js │ │ │ ├── Gruntfile.replace.js │ │ │ ├── Gruntfile.uglify.js │ │ │ ├── grunt-config.yml │ │ │ ├── gruntReplacements.yml │ │ │ ├── gruntReplacements_dev.yml │ │ │ ├── gruntReplacements_release.yml │ │ │ └── package.json │ │ └── src │ │ │ ├── .jshintrc │ │ │ ├── 06usingproperties-basic.png │ │ │ ├── exttut-06usingproperties-basic.js │ │ │ ├── exttut-06usingproperties-basic.qext │ │ │ ├── initialproperties.js │ │ │ └── properties.js │ ├── 07-Custom-Properties │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── .yo-rc.json │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── build │ │ │ └── exttut-07customproperties_dev.zip │ │ ├── dist_dev │ │ │ ├── 07customproperties.png │ │ │ ├── exttut-07customproperties.js │ │ │ ├── exttut-07customproperties.qext │ │ │ ├── initialproperties.js │ │ │ ├── lib │ │ │ │ ├── css │ │ │ │ │ └── style.css │ │ │ │ └── js │ │ │ │ │ └── extensionUtils.js │ │ │ └── properties.js │ │ ├── grunt │ │ │ ├── .jshintrc-dev │ │ │ ├── .jshintrc-release │ │ │ ├── Gruntfile.clean.js │ │ │ ├── Gruntfile.cleanempty.js │ │ │ ├── Gruntfile.compress.js │ │ │ ├── Gruntfile.copy.js │ │ │ ├── Gruntfile.js │ │ │ ├── Gruntfile.jshint.js │ │ │ ├── Gruntfile.projectconfig.js │ │ │ ├── Gruntfile.replace.js │ │ │ ├── Gruntfile.uglify.js │ │ │ ├── grunt-config.yml │ │ │ ├── gruntReplacements.yml │ │ │ ├── gruntReplacements_dev.yml │ │ │ ├── gruntReplacements_release.yml │ │ │ └── package.json │ │ └── src │ │ │ ├── .jshintrc │ │ │ ├── 07customproperties.png │ │ │ ├── exttut-07customproperties.js │ │ │ ├── exttut-07customproperties.qext │ │ │ ├── initialproperties.js │ │ │ ├── lib │ │ │ ├── css │ │ │ │ └── style.css │ │ │ └── js │ │ │ │ └── extensionUtils.js │ │ │ └── properties.js │ ├── 08-Hello-Data │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── .yo-rc.json │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── grunt │ │ │ ├── .jshintrc-dev │ │ │ ├── .jshintrc-release │ │ │ ├── Gruntfile.clean.js │ │ │ ├── Gruntfile.cleanempty.js │ │ │ ├── Gruntfile.compress.js │ │ │ ├── Gruntfile.copy.js │ │ │ ├── Gruntfile.js │ │ │ ├── Gruntfile.jshint.js │ │ │ ├── Gruntfile.less.js │ │ │ ├── Gruntfile.projectconfig.js │ │ │ ├── Gruntfile.replace.js │ │ │ ├── Gruntfile.uglify.js │ │ │ ├── grunt-config.yml │ │ │ ├── gruntReplacements.yml │ │ │ ├── gruntReplacements_dev.yml │ │ │ ├── gruntReplacements_release.yml │ │ │ └── package.json │ │ └── src │ │ │ ├── .jshintrc │ │ │ ├── 08-hellodata.png │ │ │ ├── exttut-08-hellodata.js │ │ │ └── exttut-08-hellodata.qext │ ├── 09-Loading-Resources │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── .yo-rc.json │ │ ├── CHANGELOG.yml │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── dist_dev │ │ │ ├── 09-loadingresources.png │ │ │ ├── exttut-09-loadingresources.js │ │ │ ├── exttut-09-loadingresources.qext │ │ │ └── lib │ │ │ │ ├── css │ │ │ │ └── style.css │ │ │ │ ├── images │ │ │ │ └── pic.png │ │ │ │ └── js │ │ │ │ └── extensionUtils.js │ │ ├── grunt │ │ │ ├── .jshintrc-dev │ │ │ ├── .jshintrc-release │ │ │ ├── Gruntfile.clean.js │ │ │ ├── Gruntfile.cleanempty.js │ │ │ ├── Gruntfile.compress.js │ │ │ ├── Gruntfile.copy.js │ │ │ ├── Gruntfile.js │ │ │ ├── Gruntfile.jshint.js │ │ │ ├── Gruntfile.projectconfig.js │ │ │ ├── Gruntfile.replace.js │ │ │ ├── Gruntfile.uglify.js │ │ │ ├── grunt-config.yml │ │ │ ├── gruntReplacements.yml │ │ │ ├── gruntReplacements_dev.yml │ │ │ ├── gruntReplacements_release.yml │ │ │ └── package.json │ │ └── src │ │ │ ├── .jshintrc │ │ │ ├── 09-loadingresources.png │ │ │ ├── exttut-09-loadingresources.js │ │ │ ├── exttut-09-loadingresources.qext │ │ │ └── lib │ │ │ ├── css │ │ │ └── style.css │ │ │ ├── images │ │ │ └── pic.png │ │ │ └── js │ │ │ └── extensionUtils.js │ └── 10-Hello-Data-Performancetest │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── .yo-rc.json │ │ ├── CHANGELOG.yml │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── grunt │ │ ├── .jshintrc-dev │ │ ├── .jshintrc-release │ │ ├── Gruntfile.clean.js │ │ ├── Gruntfile.cleanempty.js │ │ ├── Gruntfile.compress.js │ │ ├── Gruntfile.copy.js │ │ ├── Gruntfile.js │ │ ├── Gruntfile.jshint.js │ │ ├── Gruntfile.less.js │ │ ├── Gruntfile.projectconfig.js │ │ ├── Gruntfile.replace.js │ │ ├── Gruntfile.uglify.js │ │ ├── grunt-config.yml │ │ ├── gruntReplacements.yml │ │ ├── gruntReplacements_dev.yml │ │ ├── gruntReplacements_release.yml │ │ └── package.json │ │ └── src │ │ ├── .jshintrc │ │ ├── 10-hello-data-performancetest.png │ │ ├── exttut-10-hello-data-performancetest.js │ │ ├── exttut-10-hello-data-performancetest.qext │ │ ├── initialproperties.js │ │ ├── lib │ │ ├── css │ │ │ └── style.css │ │ ├── js │ │ │ └── extensionUtils.js │ │ └── less │ │ │ ├── _root.less │ │ │ ├── styles.less │ │ │ └── variables.less │ │ └── properties.js └── part-02 │ └── 02-AngularJS-Basics │ ├── .gitattributes │ ├── .gitignore │ ├── .yo-rc.json │ ├── CHANGELOG.yml │ ├── LICENSE.md │ ├── README.md │ ├── grunt │ ├── .jshintrc-dev │ ├── .jshintrc-release │ ├── Gruntfile.clean.js │ ├── Gruntfile.cleanempty.js │ ├── Gruntfile.compress.js │ ├── Gruntfile.copy.js │ ├── Gruntfile.js │ ├── Gruntfile.jshint.js │ ├── Gruntfile.projectconfig.js │ ├── Gruntfile.replace.js │ ├── Gruntfile.uglify.js │ ├── grunt-config.yml │ ├── gruntReplacements.yml │ ├── gruntReplacements_dev.yml │ ├── gruntReplacements_release.yml │ └── package.json │ └── src │ ├── .editorconfig │ ├── .jshintrc │ ├── 02-angularjs-basics.png │ ├── exttut-02-angularjs-basics.js │ ├── exttut-02-angularjs-basics.qext │ ├── initialproperties.js │ ├── properties.js │ └── template.ng.html ├── README.md ├── Todos.md ├── package.json └── src ├── images └── banner │ └── 06-Visualization-Extension-Tutorial--Introduction-Using-Properties.png ├── includes ├── README.md └── toc.md ├── part-00 ├── 00-toc │ └── readme.md └── 01-about │ └── readme.md ├── part-01 ├── 00-TOC │ └── readme.md ├── 01-Qlik-Sense-Extension-Tutorial │ └── readme.md ├── 02-Introduction-to-QlikSense-Visualization-Extensions │ └── readme.md ├── 03-Lets-Get-Started--Hello-World-Example │ ├── images │ │ ├── 03_description.png │ │ ├── 03_icon.png │ │ ├── 03_name.png │ │ ├── 03_output.png │ │ ├── 03_output_multiplied.png │ │ └── 03_preview.png │ └── readme.md ├── 04-Debugging-and-Web-Developer-Tools │ ├── images │ │ ├── 04_ChromeWebDevTools_Inspect_Change_Elements.png │ │ ├── 04_Chromes_Web_DevTools.png │ │ ├── 04_Console_Sample.png │ │ └── 04_DevTools_in_QlikSenseDesktop.png │ └── readme.md ├── 05-Improving-the-Hello-World-Experience │ ├── images │ │ ├── 05_DesiredResult.png │ │ ├── 05_HelloWorld_ConsoleLog.png │ │ ├── 05_InitialPropertyPanel.png │ │ ├── 05_PreviewImg_After.png │ │ └── 05_PreviewImg_Before.png │ └── readme.md ├── 06-Introduction-to-Using-Properties │ ├── images │ │ ├── 06_Accordion_Concept.png │ │ ├── 06_Console_Properties.png │ │ ├── 06_DefaultProperties.png │ │ └── 06_More_BuiltIn_Properties.png │ └── readme.md ├── 07-Custom-Properties │ ├── images │ │ ├── 07-Custom-header-with-textboxes.png │ │ ├── 07-Custom-section-with-headers-and-items.png │ │ ├── 07-Default-appearance-section.png │ │ ├── 07-Textbox-property-default.png │ │ └── 07-Two-Textboxes-default.png │ └── readme.md ├── 08-Hello-Data │ ├── images │ │ ├── 08-open-data-load-editor.png │ │ ├── 08-sample-script.png │ │ ├── 08_Custom_qInitialDataFetch.png │ │ ├── 08_Default_Object_Display.png │ │ ├── 08_Default_Property_Panel.png │ │ ├── 08_Default_qInitialDataFetch.png │ │ ├── 08_TableRendering_Result.png │ │ ├── 08_Table_ConsoleLog.png │ │ ├── 08_Table_Data.png │ │ ├── 08_Thead_All.png │ │ ├── 08_Thead_Dims.png │ │ └── 08_qMatrix_Explanation.png │ └── readme.md ├── 09-Loading-Resources │ └── readme.md ├── 10-Hello-Data-Improved │ └── readme.md ├── 11-Visualization-Extension-using-D3 │ └── readme.md └── 12-Visualization-Extension-using-HighCharts │ └── readme.md ├── part-02 ├── 01-Two-approaches-classic-one-and-the-angular-way │ └── readme.md ├── 02-The-Angular-Way--Basics │ ├── images │ │ ├── 02-AngularJS-table.png │ │ ├── 02-angular-version.png │ │ ├── 02-layout-console-output.png │ │ └── 02-output.png │ └── readme.md ├── 03-The-Angular-Way--Directives │ └── readme.md ├── 04-The-Angular-Way--Services │ └── readme.md ├── 05-The-Angular-Way--Filter │ └── readme.md ├── 06-The-Angular-Way--Events │ └── readme.md ├── 100-The-Angular-Way-Summary-and-Why │ └── readme.md └── 90-AngularJS-Recipes │ └── readme.md ├── part-03 ├── 01-exporting-data │ ├── images │ │ ├── export-failed.png │ │ ├── exportdata-context-menu.png │ │ └── qmc-export-exportdata.png │ └── readme.md └── 02-printing-extensions │ ├── images │ └── qmc-export-exportdata.png │ └── readme.md ├── part-04 └── 01-Deployment-Checklist │ └── readme.md ├── part-05 └── Advanced-More-On-Custom-Properties │ └── readme.md ├── part-07 └── 5000-Using-Bootstrap-CSS-in-Visualization-Extensions │ ├── images │ └── 5000 │ │ ├── 5000_Boostrap_Clash.png │ │ ├── 5000_Bootstrap_styled_button.png │ │ └── 5000_FolderStructure.png │ └── readme.md ├── part-09 ├── 1000-Appendix │ └── readme.md ├── 1001-Appendix-Resources │ └── readme.md ├── 1002-Troubleshooting-FAQ │ ├── images │ │ └── changes-not-reflected_DevToolsSettings.png │ └── readme.md ├── 1004-Allowed-Mime-Types-2.1.1 │ └── readme.md ├── 1050-Appendix-First-Steps-with-Qlik-Sense │ └── readme.md ├── 2011-Appendix-Whats-New-in-Qlik-Sense-1.1 │ └── readme.md └── 2013-Appendix-Whats-New-in-Qlik-Sense-2.1.1 │ ├── images │ └── 2013_usage-matrix.png │ └── readme.md ├── qsio.yml ├── readme.md └── toc-bak.md.bak /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # 4 tab indentation 12 | [*.*] 13 | indent_style = tab 14 | indent_size = 4 15 | 16 | [*.yml] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | # 2 space indentation for package.json since this is npm default 21 | [package.json] 22 | indent_style = space 23 | indent_size = 2 24 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/.gitignore: -------------------------------------------------------------------------------- 1 | [Rr]esources/ 2 | [Tt]ests/ 3 | dist/ 4 | grunt/node_modules/ 5 | 6 | 7 | # ========================= 8 | # Windows detritus 9 | # ========================= 10 | 11 | # Windows image file caches 12 | Thumbs.db 13 | ehthumbs.db 14 | 15 | # Folder config file 16 | Desktop.ini 17 | 18 | # Recycle Bin used on file shares 19 | $RECYCLE.BIN/ 20 | 21 | # Mac crap 22 | .DS_Store -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/README.md: -------------------------------------------------------------------------------- 1 | # 03-HelloWorld 2 | Qlik Sense Extension Tutorial, chapter 03, simple "Hello World". 3 | 4 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/build/ExtTut-01-HelloWorld_dev.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/03-HelloWorld/build/ExtTut-01-HelloWorld_dev.zip -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/build/ExtTut-03-HelloWorld_dev.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/03-HelloWorld/build/ExtTut-03-HelloWorld_dev.zip -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/grunt/Gruntfile.clean.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function (grunt) { 3 | 'use strict'; 4 | 5 | var config = grunt.config.data.config; 6 | 7 | return { 8 | 9 | devFiles: { 10 | options: { 11 | force: true 12 | }, 13 | src: [ 14 | '../dist/**/*.bak', 15 | '../dist/**/*.less', 16 | '../dist/**/*.tmpl' 17 | ], 18 | filter: 'isFile' 19 | }, 20 | empty_dist: { 21 | options: { 22 | force: true 23 | }, 24 | src: [ 25 | '../dist/**/*' 26 | ] 27 | }, 28 | empty_desktop: { 29 | options: { 30 | force: true 31 | }, 32 | src: [ 33 | config.general.LocalExtensionPath + '/' + config.general.ExtensionNameSafe + '/**/*' 34 | ] 35 | } 36 | }; 37 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/grunt/Gruntfile.cleanempty.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function( grunt ) { 3 | 'use strict'; 4 | 5 | var config = grunt.config.data.config; 6 | 7 | return { 8 | 9 | options: { 10 | force: true 11 | }, 12 | all: { 13 | options: { 14 | files: false 15 | }, 16 | src: ['../dist/**/*'] 17 | } 18 | 19 | }; 20 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/grunt/Gruntfile.compress.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function (grunt) { 3 | 'use strict'; 4 | 5 | var config = grunt.config.data.config; 6 | 7 | return { 8 | 9 | dev: { 10 | options: { 11 | archive: '../build/' + config.general.ExtensionNameSafe +'_dev.zip' 12 | }, 13 | files: [ 14 | {expand: true, cwd: '../dist/', src: ['**'], dest: '/'} 15 | ] 16 | }, 17 | release: { 18 | options: { 19 | archive: '../build/' + config.general.ExtensionNameSafe + '_' + '.zip' 20 | }, 21 | files: [ 22 | {expand: true, cwd: '../dist/', src: ['**'], dest: '/'} 23 | ] 24 | } 25 | }; 26 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/grunt/Gruntfile.copy.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function (grunt) { 3 | 'use strict'; 4 | 5 | var config = grunt.config.data.config; 6 | 7 | return { 8 | copy_to_dist: { 9 | expand: true, // allow dynamic building 10 | cwd: '../src/', // change base dir 11 | //src: ['**', '!docs/**'], // source files mask 12 | src: ['**'], 13 | dest: '../dist/', // destination folder 14 | flatten: false // remove all unnecessary nesting 15 | }, 16 | copy_to_desktop: { 17 | expand: true, 18 | cwd: '../dist/', 19 | src: '**', 20 | dest: config.general.LocalExtensionPath + '/' + config.general.ExtensionNameSafe + '/' 21 | } 22 | }; 23 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/grunt/Gruntfile.replace.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function (grunt) { 3 | 4 | 'use strict'; 5 | 6 | var repl = grunt.config.data.replacements; 7 | 8 | // Replace variables like the Urls for the help, the version, etc. 9 | return { 10 | 11 | general: { 12 | options: { 13 | patterns: [ 14 | { 15 | json: repl.general 16 | } 17 | ] 18 | }, 19 | files: [ 20 | { 21 | expand: true, 22 | flatten: true, 23 | src: ['../dist/*.*'], 24 | dest: '../dist/'} 25 | ] 26 | }, 27 | dev: { 28 | options: { 29 | patterns: [ 30 | { 31 | json: repl.dev 32 | } 33 | ] 34 | }, 35 | files: [ 36 | { 37 | expand: true, 38 | flatten: true, 39 | src: ['../dist/*.*'], 40 | dest: '../dist/'} 41 | ] 42 | }, 43 | release: { 44 | options: { 45 | patterns: [ 46 | { 47 | json: repl.release 48 | } 49 | ] 50 | }, 51 | files: [ 52 | { 53 | expand: true, 54 | flatten: true, 55 | src: ['../dist/*.*'], 56 | dest: '../dist/'} 57 | ] 58 | } 59 | }; 60 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/grunt/grunt-config.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General Settings 3 | general: 4 | LocalExtensionPath: "d:\\Documents\\Qlik\\Sense\\Extensions" 5 | ExtensionName: "ExtTut-03-HelloWorld" 6 | ExtensionNameSafe: "ExtTut-03-HelloWorld" 7 | ExtensionNamespace: "swr-" 8 | Version: '0.0.1' 9 | 10 | # ------------------------------------------------------------------- 11 | # Settings for the Dev build 12 | dev: 13 | less: 14 | lessCompress: false 15 | lessYuiCompress: false 16 | lessCleanCss: false 17 | lessOptimization: 2 18 | uglify: 19 | mangle: false 20 | drop_console: false 21 | beautify: true 22 | preserveCommments: true 23 | compress: false 24 | 25 | # ------------------------------------------------------------------- 26 | # Settings for the Release build 27 | release: 28 | less: 29 | lessCompress: true 30 | lessYuiCompress: true 31 | lessCleanCss: true 32 | lessOptimization: 2 33 | uglify: 34 | mangle: true 35 | drop_console: true 36 | beautify: false 37 | preserveCommments: false 38 | compress: true -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/grunt/gruntReplacements.yml: -------------------------------------------------------------------------------- 1 | version: 0.0.1 -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/grunt/gruntReplacements_dev.yml: -------------------------------------------------------------------------------- 1 | isDebug: true -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/grunt/gruntReplacements_release.yml: -------------------------------------------------------------------------------- 1 | isDebug: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/grunt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ExtTut-01-HelloWorld", 3 | "version": "0.0.1", 4 | "description": "Extension Tutorial, Session 1, Simple Hello World.", 5 | "main": "gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "Qlik Sense Extension", 11 | "Qlik Sense", 12 | "QlikSense", 13 | "Extension" 14 | ], 15 | "author": "Stefan Walther", 16 | "license": "MIT", 17 | "devDependencies": { 18 | "grunt": "~0.4.2", 19 | "grunt-contrib-copy": "~0.6.0", 20 | "grunt-contrib-uglify": "~0.4.0", 21 | "grunt-contrib-clean": "~0.5.0", 22 | "grunt-contrib-compress": "~0.8.0", 23 | "grunt-cleanempty": "~0.2.1", 24 | "grunt-contrib-cssmin": "~0.10.0", 25 | "grunt-replace": "~0.7.8", 26 | "grunt-contrib-less": "~0.11.0" 27 | } 28 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/03-HelloWorld/src/exttut-03-helloworld.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ExtTut-03-HelloWorld", 3 | "description": "Extension Tutorial, chapter 3, simple \"Hello World\".", 4 | "icon": "extension", 5 | "type": "visualization", 6 | "version": "0.1", 7 | "author": "Stefan Walther" 8 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # ========================= 5 | # Custom for Visual Studio 6 | # ========================= 7 | *.cs diff=csharp 8 | *.sln merge=union 9 | *.csproj merge=union 10 | *.vbproj merge=union 11 | *.fsproj merge=union 12 | *.dbproj merge=union 13 | 14 | # ========================= 15 | # Standard to msysgit 16 | # ========================= 17 | *.doc diff=astextplain 18 | *.DOC diff=astextplain 19 | *.docx diff=astextplain 20 | *.DOCX diff=astextplain 21 | *.dot diff=astextplain 22 | *.DOT diff=astextplain 23 | *.pdf diff=astextplain 24 | *.PDF diff=astextplain 25 | *.rtf diff=astextplain 26 | *.RTF diff=astextplain 27 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-qsextension": { 3 | "advancedMode": false, 4 | "extensionName": "exttut-04-Debugging", 5 | "extensionNameSafe": "exttut-04-Debugging", 6 | "extensionNamespace": "", 7 | "extensionDescription": "Sample code for chapter 04", 8 | "authorName": "Stefan Walther", 9 | "license": "mit", 10 | "publishingYear": 2015, 11 | "creationDate": "2015-03-04", 12 | "licenceGenerated": "> \r\n> The MIT License (MIT)\r\n> \r\n> Copyright (c) 2015 Stefan Walther\r\n> \r\n> Permission is hereby granted, free of charge, to any person obtaining a copy\r\n> of this software and associated documentation files (the \"Software\"), to deal\r\n> in the Software without restriction, including without limitation the rights\r\n> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n> copies of the Software, and to permit persons to whom the Software is\r\n> furnished to do so, subject to the following conditions:\r\n> \r\n> The above copyright notice and this permission notice shall be included in all\r\n> copies or substantial portions of the Software.\r\n> \r\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n> SOFTWARE.\r\n> " 13 | } 14 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/README.md: -------------------------------------------------------------------------------- 1 | # 04-Debugging 2 | Qlik Sense Extension Tutorial, Chapter 04, Deubgging and Web Developer Tools 3 | 4 | ## Author 5 | 6 | **Stefan Walther** 7 | 8 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/.jshintrc-dev: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": true, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true, 75 | "_": true, 76 | "console": true 77 | } 78 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/.jshintrc-release: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true, 75 | "_": true 76 | } 77 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/Gruntfile.clean.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function (grunt) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks('grunt-contrib-clean'); 6 | return { 7 | 8 | devFiles: { 9 | options: { 10 | force: true 11 | }, 12 | src: [ 13 | '../dist/**/*.bak', 14 | '../dist/**/*.less', 15 | '../dist/**/*.tmpl' 16 | ], 17 | filter: 'isFile' 18 | }, 19 | empty_dist: { 20 | options: { 21 | force: true 22 | }, 23 | src: [ 24 | '../dist/**/*' 25 | ] 26 | }, 27 | empty_desktop: { 28 | options: { 29 | force: true 30 | }, 31 | src: [ 32 | '<%=projectconfig.general.ExtensionNamespace%>/<%=projectconfig.general.ExtensionNameSafe%>/**/*' 33 | ] 34 | } 35 | }; 36 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/Gruntfile.cleanempty.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks('grunt-cleanempty'); 6 | return { 7 | 8 | options: { 9 | force: true 10 | }, 11 | all: { 12 | options: { 13 | files: false 14 | }, 15 | src: ['../dist/**/*'] 16 | } 17 | 18 | }; 19 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/Gruntfile.compress.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-compress' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_dev.zip' 11 | }, 12 | files: [ 13 | { 14 | expand: true, 15 | cwd: '../dist/', 16 | src: ['**/*.*'], 17 | dest: '/' 18 | } 19 | ] 20 | }, 21 | release: { 22 | options: { 23 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_v<%=projectconfig.general.Version%>.zip' 24 | }, 25 | files: [ 26 | { 27 | expand: true, 28 | cwd: '../dist/', 29 | src: ['**/*.*'], 30 | dest: '/' 31 | } 32 | ] 33 | }, 34 | release_latest: { 35 | options: { 36 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_latest.zip' 37 | }, 38 | files: [ 39 | { 40 | expand: true, 41 | cwd: '../dist/', 42 | src: ['**/*.*'], 43 | dest: '/' 44 | } 45 | ] 46 | }, 47 | source: { 48 | options: { 49 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe%>_src_v<%=projectconfig.general.Version%>.zip' 50 | }, 51 | files: [ 52 | { 53 | expand: true, 54 | cwd: '../', 55 | src: ['src/**/*', 'grunt/**/*', '!grunt/node_modules/**/*'], 56 | dest: '/' 57 | } 58 | ] 59 | } 60 | }; 61 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/Gruntfile.copy.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-copy' ); 6 | return { 7 | options: { 8 | processContentExclude: ['**/*.{png,gif,jpg,ico,psd}'] 9 | }, 10 | copy_to_dist: { 11 | expand: true, // allow dynamic building 12 | cwd: '../src/', // change base dir 13 | //src: ['**', '!docs/**'], // source files mask 14 | src: ['**'], 15 | dest: '../dist/', // destination folder 16 | flatten: false // remove all unnecessary nesting 17 | }, 18 | copy_to_desktop: { 19 | expand: true, 20 | cwd: '../dist/', 21 | src: '**', 22 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 23 | } 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/Gruntfile.jshint.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-jshint' ); 6 | return { 7 | dev: { 8 | options: { 9 | jshintrc: ".jshintrc-dev", 10 | ignores: [] 11 | }, 12 | defaults: ["<%=projectconfig.jsSources.dev%>"] 13 | }, 14 | release: { 15 | options: { 16 | jshintrc: ".jshintrc-release", 17 | ignores: [] 18 | }, 19 | defaults: ["<%=projectconfig.jsSources.release%>"] 20 | } 21 | 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/Gruntfile.projectconfig.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | var YAML = require( 'yamljs' ); 3 | module.exports = function ( grunt ) { 4 | 'use strict'; 5 | return YAML.load( 'grunt-config.yml' ); 6 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/Gruntfile.replace.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-replace' ); 6 | 7 | /** 8 | * Replace variables like the Urls for the help, the version, etc. 9 | */ 10 | return { 11 | 12 | general: { 13 | options: { 14 | patterns: [ 15 | { 16 | json: grunt.file.readYAML( 'gruntReplacements.yml' ) 17 | } 18 | ] 19 | }, 20 | files: [ 21 | { 22 | expand: true, 23 | flatten: false, 24 | src: ['../dist/**/*.*', '!../dist/**/*.{min.js,png,gif,jpg,ico,psd,eot,svg,ttf,woff}'], 25 | dest: '../dist/' 26 | } 27 | ] 28 | }, 29 | dev: { 30 | options: { 31 | patterns: [ 32 | { 33 | json: grunt.file.readYAML( 'gruntReplacements_dev.yml' ) 34 | } 35 | ] 36 | }, 37 | files: [ 38 | { 39 | expand: true, 40 | flatten: false, 41 | src: ['../dist/*.*', '!../dist/**/*.{min.js,png,gif,jpg,ico,psd,eot,svg,ttf,woff}'], 42 | dest: '../dist/' 43 | } 44 | ] 45 | }, 46 | release: { 47 | options: { 48 | patterns: [ 49 | { 50 | json: grunt.file.readYAML( 'gruntReplacements_release.yml' ) 51 | } 52 | ] 53 | }, 54 | files: [ 55 | { 56 | expand: true, 57 | flatten: false, 58 | src: ['../dist/**/*.*', '!../dist/**/*.{min.js,png,gif,jpg,ico,psd,eot,svg,ttf,woff}'], 59 | dest: '../dist/' 60 | } 61 | ] 62 | } 63 | }; 64 | }; 65 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/Gruntfile.uglify.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | /*jshint 3 | camelcase: false 4 | */ 5 | module.exports = function ( grunt ) { 6 | 'use strict'; 7 | 8 | grunt.loadNpmTasks( 'grunt-contrib-uglify' ); 9 | return { 10 | 11 | options: { 12 | mangle: ('<%= projectconfig.release.uglify.mangle%>' === 'true'), 13 | beautify: ('<%= projectconfig.release.uglify.beautify%>' === 'true'), 14 | preserveComments: ('<%= projectconfig.release.uglify.preserveComments%>' === 'true'), 15 | compress: { 16 | drop_console: ('<%= projectconfig.release.uglify.drop_console%>' === 'true') 17 | } 18 | }, 19 | release: { 20 | files: [ 21 | { 22 | src: ['../dist/<%= projectconfig.general.ExtensionNamespace %><%= projectconfig.general.ExtensionNameSafe%>.js'], 23 | dest: '../dist/<%= projectconfig.general.ExtensionNamespace %><%= projectconfig.general.ExtensionNameSafe%>.js' 24 | }, 25 | { 26 | src: ['../dist/properties.js'], 27 | dest: '../dist/properties.js' 28 | }, 29 | { 30 | src: ['../dist/initialproperties.js'], 31 | dest: '../dist/initialproperties.js' 32 | } 33 | ] 34 | } 35 | }; 36 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/gruntReplacements.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in both the dev and release 5 | # task 6 | # 7 | # In your code just use @@variable 8 | # ------------------------------------------------------------------- 9 | 10 | # You have to have at least one variable here 11 | dummy: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/gruntReplacements_dev.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the dev task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: true -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/gruntReplacements_release.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the release task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/grunt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Grunt-Deployment-exttut-04-Debugging", 3 | "version": "0.0.1", 4 | "description": "Grunt tasks (dev + release) for the Qlik Sense extension exttut-04-Debugging", 5 | "main": "gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "Qlik Sense Extension", 11 | "qliksense-visualization-extension", 12 | "Qlik Sense", 13 | "QlikSense", 14 | "Extension" 15 | ], 16 | "author": "Stefan Walther", 17 | "license": "MIT", 18 | "dependencies": { 19 | "grunt": "~0.4.5", 20 | "grunt-contrib-clean": "~0.6.0", 21 | "grunt-cleanempty": "~1.0.3", 22 | "grunt-contrib-compress": "~0.13.0", 23 | "grunt-contrib-copy": "~0.8.0", 24 | "grunt-contrib-jshint": "^0.11.0", 25 | "grunt-contrib-less": "~1.0.0", 26 | "grunt-replace": "~0.8.0", 27 | "grunt-contrib-uglify": "~0.8.0", 28 | "q": "^1.2.0", 29 | "winreg": "0.0.12", 30 | "async": "^0.9.0", 31 | "yamljs": "^0.2.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/src/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true 75 | } 76 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/src/exttut-04-debugging.js: -------------------------------------------------------------------------------- 1 | define( [], 2 | function () { 3 | 'use strict'; 4 | 5 | return { 6 | paint: function ( $element, layout ) { 7 | 8 | var err = { 9 | message: 'Something went wrong', 10 | errCode: 'bla' 11 | }; 12 | 13 | console.info( 'We are re-painting the extension' ); 14 | console.error( 'Oops, we haven an error', err ); 15 | console.log( 'We are here' ); 16 | console.log( 'layout', layout ); 17 | 18 | } 19 | }; 20 | 21 | } ) 22 | ; 23 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/src/exttut-04-debugging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/04-Debugging/src/exttut-04-debugging.png -------------------------------------------------------------------------------- /Chapters-Source/part-01/04-Debugging/src/exttut-04-debugging.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "exttut-04-Debugging", 3 | "description" : "Sample code for chapter 04", 4 | "icon" : "", 5 | "type" : "visualization", 6 | "version": "@@version", 7 | "preview" : "exttut-04-debugging.png", 8 | "author": "Stefan Walther" 9 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/.gitignore: -------------------------------------------------------------------------------- 1 | [Rr]esources/ 2 | [Tt]ests/ 3 | dist/ 4 | grunt/node_modules/ 5 | 6 | # ========================= 7 | # Windows detritus 8 | # ========================= 9 | 10 | # Windows image file caches 11 | Thumbs.db 12 | ehthumbs.db 13 | 14 | # Folder config file 15 | Desktop.ini 16 | 17 | # Recycle Bin used on file shares 18 | $RECYCLE.BIN/ 19 | 20 | # Mac crap 21 | .DS_Store -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-qsextension": { 3 | "advancedMode": false, 4 | "extensionName": "exttut-05-Improving-HelloWorld", 5 | "extensionNameSafe": "exttut-04-Improving-HelloWorld", 6 | "extensionNamespace": "", 7 | "extensionDescription": "Sample code for chapter 05, improving the \"Hello World\" experience", 8 | "authorName": "Stefan Walther", 9 | "license": "mit", 10 | "publishingYear": 2015, 11 | "creationDate": "2015-03-04", 12 | "licenceGenerated": "> \r\n> The MIT License (MIT)\r\n> \r\n> Copyright (c) 2015 Stefan Walther\r\n> \r\n> Permission is hereby granted, free of charge, to any person obtaining a copy\r\n> of this software and associated documentation files (the \"Software\"), to deal\r\n> in the Software without restriction, including without limitation the rights\r\n> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n> copies of the Software, and to permit persons to whom the Software is\r\n> furnished to do so, subject to the following conditions:\r\n> \r\n> The above copyright notice and this permission notice shall be included in all\r\n> copies or substantial portions of the Software.\r\n> \r\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n> SOFTWARE.\r\n> " 13 | } 14 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/README.md: -------------------------------------------------------------------------------- 1 | # 05-Improving-HelloWorld 2 | Qlik Sense Extension Tutorial, Chapter 05, improving the "Hello World" experience 3 | 4 | ## Author 5 | 6 | **Stefan Walther** 7 | 8 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/build/ExtTut-05-Improving-HelloWorld_dev.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/05-Improving-HelloWorld/build/ExtTut-05-Improving-HelloWorld_dev.zip -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/grunt/Gruntfile.clean.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function (grunt) { 3 | 'use strict'; 4 | 5 | var config = grunt.config.data.config; 6 | 7 | return { 8 | 9 | devFiles: { 10 | options: { 11 | force: true 12 | }, 13 | src: [ 14 | '../dist/**/*.bak', 15 | '../dist/**/*.less', 16 | '../dist/**/*.tmpl' 17 | ], 18 | filter: 'isFile' 19 | }, 20 | empty_dist: { 21 | options: { 22 | force: true 23 | }, 24 | src: [ 25 | '../dist/**/*' 26 | ] 27 | }, 28 | empty_desktop: { 29 | options: { 30 | force: true 31 | }, 32 | src: [ 33 | config.general.LocalExtensionPath + '/' + config.general.ExtensionNameSafe + '/**/*' 34 | ] 35 | } 36 | }; 37 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/grunt/Gruntfile.cleanempty.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function( grunt ) { 3 | 'use strict'; 4 | 5 | var config = grunt.config.data.config; 6 | 7 | return { 8 | 9 | options: { 10 | force: true 11 | }, 12 | all: { 13 | options: { 14 | files: false 15 | }, 16 | src: ['../dist/**/*'] 17 | } 18 | 19 | }; 20 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/grunt/Gruntfile.compress.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function (grunt) { 3 | 'use strict'; 4 | 5 | var config = grunt.config.data.config; 6 | 7 | return { 8 | 9 | dev: { 10 | options: { 11 | archive: '../build/' + config.general.ExtensionNameSafe +'_dev.zip' 12 | }, 13 | files: [ 14 | {expand: true, cwd: '../dist/', src: ['**'], dest: '/'} 15 | ] 16 | }, 17 | release: { 18 | options: { 19 | archive: '../build/' + config.general.ExtensionNameSafe + '_' + '.zip' 20 | }, 21 | files: [ 22 | {expand: true, cwd: '../dist/', src: ['**'], dest: '/'} 23 | ] 24 | } 25 | }; 26 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/grunt/Gruntfile.copy.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function (grunt) { 3 | 'use strict'; 4 | 5 | var config = grunt.config.data.config; 6 | 7 | return { 8 | copy_to_dist: { 9 | expand: true, // allow dynamic building 10 | cwd: '../src/', // change base dir 11 | //src: ['**', '!docs/**'], // source files mask 12 | src: ['**'], 13 | dest: '../dist/', // destination folder 14 | flatten: false // remove all unnecessary nesting 15 | }, 16 | copy_to_desktop: { 17 | expand: true, 18 | cwd: '../dist/', 19 | src: '**', 20 | dest: config.general.LocalExtensionPath + '/' + config.general.ExtensionNameSafe + '/' 21 | } 22 | }; 23 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/grunt/Gruntfile.replace.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 4 | 'use strict'; 5 | 6 | var repl = grunt.config.data.replacements; 7 | 8 | // Replace variables like the Urls for the help, the version, etc. 9 | return { 10 | 11 | general: { 12 | options: { 13 | patterns: [ 14 | { 15 | json: repl.general 16 | } 17 | ] 18 | }, 19 | files: [ 20 | { 21 | expand: true, 22 | flatten: true, 23 | src: ['../dist/*.*', '!../dist/**/*.{png,gif,jpg,ico,psd,eot,svg,ttf,woff}'], 24 | dest: '../dist/' 25 | } 26 | ] 27 | }, 28 | dev: { 29 | options: { 30 | patterns: [ 31 | { 32 | json: repl.dev 33 | } 34 | ] 35 | }, 36 | files: [ 37 | { 38 | expand: true, 39 | flatten: true, 40 | src: ['../dist/*.*', '!../dist/**/*.{png,gif,jpg,ico,psd,eot,svg,ttf,woff}'], 41 | dest: '../dist/' 42 | } 43 | ] 44 | }, 45 | release: { 46 | options: { 47 | patterns: [ 48 | { 49 | json: repl.release 50 | } 51 | ] 52 | }, 53 | files: [ 54 | { 55 | expand: true, 56 | flatten: true, 57 | src: ['../dist/*.*', '!../dist/**/*.{png,gif,jpg,ico,psd,eot,svg,ttf,woff}'], 58 | dest: '../dist/' 59 | } 60 | ] 61 | } 62 | }; 63 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/grunt/grunt-config.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General Settings 3 | general: 4 | LocalExtensionPath: "d:\\Documents\\Qlik\\Sense\\Extensions" 5 | ExtensionName: "ExtTut-05-Improving-HelloWorld" 6 | ExtensionNameSafe: "ExtTut-05-Improving-HelloWorld" 7 | ExtensionNamespace: "swr-" 8 | Version: '0.0.1' 9 | 10 | # ------------------------------------------------------------------- 11 | # Settings for the Dev build 12 | dev: 13 | less: 14 | lessCompress: false 15 | lessYuiCompress: false 16 | lessCleanCss: false 17 | lessOptimization: 2 18 | uglify: 19 | mangle: false 20 | drop_console: false 21 | beautify: true 22 | preserveCommments: true 23 | compress: false 24 | 25 | # ------------------------------------------------------------------- 26 | # Settings for the Release build 27 | release: 28 | less: 29 | lessCompress: true 30 | lessYuiCompress: true 31 | lessCleanCss: true 32 | lessOptimization: 2 33 | uglify: 34 | mangle: true 35 | drop_console: true 36 | beautify: false 37 | preserveCommments: false 38 | compress: true -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/grunt/gruntReplacements.yml: -------------------------------------------------------------------------------- 1 | version: 0.0.1 -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/grunt/gruntReplacements_dev.yml: -------------------------------------------------------------------------------- 1 | isDebug: true -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/grunt/gruntReplacements_release.yml: -------------------------------------------------------------------------------- 1 | isDebug: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/grunt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ExtTut-01-HelloWorld", 3 | "version": "0.0.1", 4 | "description": "Extension Tutorial, Session 1, Simple Hello World.", 5 | "main": "gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "Qlik Sense Extension", 11 | "Qlik Sense", 12 | "QlikSense", 13 | "Extension" 14 | ], 15 | "author": "Stefan Walther", 16 | "license": "MIT", 17 | "devDependencies": { 18 | "grunt": "~0.4.2", 19 | "grunt-contrib-copy": "~0.6.0", 20 | "grunt-contrib-uglify": "~0.4.0", 21 | "grunt-contrib-clean": "~0.5.0", 22 | "grunt-contrib-compress": "~0.8.0", 23 | "grunt-cleanempty": "~0.2.1", 24 | "grunt-contrib-cssmin": "~0.10.0", 25 | "grunt-replace": "~0.7.8", 26 | "grunt-contrib-less": "~0.11.0" 27 | } 28 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/src/ImprovedHelloWorld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/05-Improving-HelloWorld/src/ImprovedHelloWorld.png -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/src/exttut-05-improving-helloworld.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | 'jquery' 3 | ], 4 | function ( $ ) { 5 | 'use strict'; 6 | 7 | return { 8 | 9 | // Define how our property panel looks like 10 | definition: { 11 | type: "items", 12 | component: "accordion", 13 | items: { 14 | appearancePanel: { 15 | uses: "settings", 16 | items: { 17 | MyStringProp: { 18 | ref: "myDynamicOutput", 19 | label: "Hello World Text", 20 | type: "string", 21 | defaultValue: "Hello World" 22 | } 23 | } 24 | } 25 | } 26 | }, 27 | // Paint/Rendering logic 28 | paint: function ( $element, layout ) { 29 | 30 | console.log( layout ); 31 | 32 | $element.empty(); 33 | var $helloWorld = $( document.createElement( 'div' ) ); 34 | $helloWorld.html( 'Hello World from the extension "05-ExtTut-HelloWorld"
' ); 35 | $element.append( $helloWorld ); 36 | } 37 | }; 38 | } ); -------------------------------------------------------------------------------- /Chapters-Source/part-01/05-Improving-HelloWorld/src/exttut-05-improving-helloworld.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ExtTut-05-Improving-HelloWorld", 3 | "description": "Extension tutorial, chapter 5, improving \"Hello World\".", 4 | "icon": "extension", 5 | "type": "visualization", 6 | "version": "0.1", 7 | "author": "Stefan Walther", 8 | "preview": "ImprovedHelloWorld.png" 9 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # ========================= 5 | # Custom for Visual Studio 6 | # ========================= 7 | *.cs diff=csharp 8 | *.sln merge=union 9 | *.csproj merge=union 10 | *.vbproj merge=union 11 | *.fsproj merge=union 12 | *.dbproj merge=union 13 | 14 | # ========================= 15 | # Standard to msysgit 16 | # ========================= 17 | *.doc diff=astextplain 18 | *.DOC diff=astextplain 19 | *.docx diff=astextplain 20 | *.DOCX diff=astextplain 21 | *.dot diff=astextplain 22 | *.DOT diff=astextplain 23 | *.pdf diff=astextplain 24 | *.PDF diff=astextplain 25 | *.rtf diff=astextplain 26 | *.RTF diff=astextplain 27 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## Version 0.0.1 4 | Date: 2015-05-11 5 | 6 | * Initial Commit 7 | 8 | --- 9 | * Basic template and build system created using the [Yeoman Generator for Qlik Sense Extensions](https://github.com/stefanwalther/generator-qsExtension) 10 | 11 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/LICENSE.md: -------------------------------------------------------------------------------- 1 | **06 Using Properties - Basic Qlik Sense Extension** is licensed under the "MIT" license: 2 | 3 | * [License](#license) 4 | * [External Libraries](#external libraries) 5 | 6 | --- 7 | 8 | ## License 9 | 10 | > 11 | > The MIT License (MIT) 12 | > 13 | > Copyright (c) 2015 Stefan Walther 14 | > 15 | > Permission is hereby granted, free of charge, to any person obtaining a copy 16 | > of this software and associated documentation files (the "Software"), to deal 17 | > in the Software without restriction, including without limitation the rights 18 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | > copies of the Software, and to permit persons to whom the Software is 20 | > furnished to do so, subject to the following conditions: 21 | > 22 | > The above copyright notice and this permission notice shall be included in all 23 | > copies or substantial portions of the Software. 24 | > 25 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | > SOFTWARE. 32 | > 33 | 34 | ## External Libraries 35 | 36 | These external libraries are used within this solution. Many thanks to the authors! 37 | 38 | **Library 1** 39 | * Name: 40 | * License: 41 | * Url: 42 | * Author: 43 | 44 | **Library 2** 45 | * Name: 46 | * License: 47 | * Url: 48 | * Author: 49 | 50 | --- 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/README.md: -------------------------------------------------------------------------------- 1 | # 06 Using Properties - Basic 2 | > Basic example of using built-in properties. 3 | 4 | 5 | ## Author 6 | 7 | **Stefan Walther** 8 | 9 | ## Change Log 10 | 11 | See [CHANGELOG.md](CHANGELOG.md) 12 | 13 | ## License & Copyright 14 | The software is made available "AS IS" without any warranty of any kind under the MIT License (MIT). 15 | 16 | See [Additional license information for this solution.](LICENSE.md) 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/.jshintrc-release: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true, 75 | "_": true 76 | } 77 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/Gruntfile.clean.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-clean' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | force: true 11 | }, 12 | src: [ 13 | '../dist_dev/**/*.bak', 14 | '../dist_dev/**/*.less', 15 | '../dist_dev/**/*.tmpl' 16 | ], 17 | filter: 'isFile' 18 | }, 19 | release: { 20 | options: { 21 | force: true 22 | }, 23 | src: [ 24 | '../dist/**/*.bak', 25 | '../dist/**/*.less', 26 | '../dist/**/*.tmpl' 27 | ], 28 | filter: 'isFile' 29 | }, 30 | empty_dist_dev: { 31 | options: { 32 | force: true 33 | }, 34 | src: [ 35 | '../dist_dev/**/*' 36 | ] 37 | }, 38 | empty_dist: { 39 | options: { 40 | force: true 41 | }, 42 | src: [ 43 | '../dist/**/*' 44 | ] 45 | }, 46 | empty_desktop: { 47 | options: { 48 | force: true 49 | }, 50 | src: [ 51 | '<%=projectconfig.general.ExtensionNamespace%>/<%=projectconfig.general.ExtensionNameSafe%>/**/*' 52 | ] 53 | } 54 | }; 55 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/Gruntfile.cleanempty.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks('grunt-cleanempty'); 6 | return { 7 | 8 | options: { 9 | force: true 10 | }, 11 | all: { 12 | options: { 13 | files: false 14 | }, 15 | src: ['../dist/**/*'] 16 | } 17 | 18 | }; 19 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/Gruntfile.compress.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-compress' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_dev.zip' 11 | }, 12 | files: [ 13 | { 14 | expand: true, 15 | cwd: '../dist_dev/', 16 | src: ['**/*.*'], 17 | dest: '/' 18 | } 19 | ] 20 | }, 21 | release: { 22 | options: { 23 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_v<%=projectconfig.general.Version%>.zip' 24 | }, 25 | files: [ 26 | { 27 | expand: true, 28 | cwd: '../dist/', 29 | src: ['**/*.*'], 30 | dest: '/' 31 | } 32 | ] 33 | }, 34 | release_latest: { 35 | options: { 36 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_latest.zip' 37 | }, 38 | files: [ 39 | { 40 | expand: true, 41 | cwd: '../dist/', 42 | src: ['**/*.*'], 43 | dest: '/' 44 | } 45 | ] 46 | }, 47 | source: { 48 | options: { 49 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe%>_src_v<%=projectconfig.general.Version%>.zip' 50 | }, 51 | files: [ 52 | { 53 | expand: true, 54 | cwd: '../', 55 | src: ['src/**/*', 'grunt/**/*', '!grunt/node_modules/**/*'], 56 | dest: '/' 57 | } 58 | ] 59 | } 60 | }; 61 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/Gruntfile.copy.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-copy' ); 6 | return { 7 | options: { 8 | processContentExclude: ['**/*.{png,gif,jpg,ico,psd}'] 9 | }, 10 | copy_to_dist_dev: { 11 | expand: true, // allow dynamic building 12 | cwd: '../src/', // change base dir 13 | //src: ['**', '!docs/**'], // source files mask 14 | src: ['**'], 15 | dest: '../dist_dev/', // destination folder 16 | flatten: false // remove all unnecessary nesting 17 | }, 18 | copy_to_dist_release: { 19 | expand: true, // allow dynamic building 20 | cwd: '../src/', // change base dir 21 | //src: ['**', '!docs/**'], // source files mask 22 | src: ['**'], 23 | dest: '../dist/', // destination folder 24 | flatten: false // remove all unnecessary nesting 25 | }, 26 | copy_to_desktop_dev: { 27 | expand: true, 28 | cwd: '../dist_dev/', 29 | src: '**', 30 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 31 | }, 32 | copy_to_desktop_release: { 33 | expand: true, 34 | cwd: '../dist/', 35 | src: '**', 36 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 37 | } 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/Gruntfile.jshint.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-jshint' ); 6 | return { 7 | dev: { 8 | options: { 9 | jshintrc: ".jshintrc-dev", 10 | ignores: [] 11 | }, 12 | defaults: ["<%=projectconfig.jsSources.dev%>"] 13 | }, 14 | release: { 15 | options: { 16 | jshintrc: ".jshintrc-release", 17 | ignores: [] 18 | }, 19 | defaults: ["<%=projectconfig.jsSources.release%>"] 20 | } 21 | 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/Gruntfile.projectconfig.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | var YAML = require( 'yamljs' ); 3 | module.exports = function ( grunt ) { 4 | 'use strict'; 5 | return YAML.load( 'grunt-config.yml' ); 6 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/Gruntfile.uglify.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | /*jshint 3 | camelcase: false 4 | */ 5 | module.exports = function ( grunt ) { 6 | 'use strict'; 7 | 8 | grunt.loadNpmTasks( 'grunt-contrib-uglify' ); 9 | return { 10 | 11 | options: { 12 | mangle: '<%= projectconfig.release.uglify.mangle%>', 13 | beautify: '<%= projectconfig.release.uglify.beautify%>', 14 | preserveComments: '<%= projectconfig.release.uglify.preserveComments%>', 15 | compress: { 16 | drop_console: '<%= projectconfig.release.uglify.drop_console%>' 17 | } 18 | }, 19 | release: { 20 | files: [ 21 | { 22 | src: ['./../dist/**/*.js', '!./../dist/**/*.min.js'], 23 | dest: './../dist/', 24 | expand: true 25 | } 26 | ] 27 | } 28 | }; 29 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/gruntReplacements.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in both the dev and release 5 | # task 6 | # 7 | # In your code just use @@variable 8 | # ------------------------------------------------------------------- 9 | 10 | # You have to have at least one variable here 11 | dummy: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/gruntReplacements_dev.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the dev task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: true -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/gruntReplacements_release.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the release task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/grunt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Grunt-Deployment-06UsingProperties-Basic", 3 | "version": "0.0.1", 4 | "description": "Grunt tasks (dev + release) for the Qlik Sense extension 06 Using Properties - Basic", 5 | "main": "gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "Qlik Sense Extension", 11 | "qliksense-visualization-extension", 12 | "Qlik Sense", 13 | "QlikSense", 14 | "Extension" 15 | ], 16 | "author": "Stefan Walther", 17 | "license": "MIT", 18 | "dependencies": { 19 | "grunt": "~0.4.5", 20 | "grunt-contrib-clean": "~0.6.0", 21 | "grunt-cleanempty": "~1.0.3", 22 | "grunt-contrib-compress": "~0.13.0", 23 | "grunt-contrib-copy": "~0.8.0", 24 | "grunt-contrib-jshint": "^0.11.0", 25 | "grunt-contrib-less": "~1.0.0", 26 | "grunt-replace": "~0.8.0", 27 | "grunt-contrib-uglify": "~0.8.0", 28 | "q": "^1.2.0", 29 | "winreg": "0.0.12", 30 | "async": "^0.9.0", 31 | "yamljs": "^0.2.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/src/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true 75 | } 76 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/src/06usingproperties-basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/06-Using-Properties-Basic/src/06usingproperties-basic.png -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/src/exttut-06usingproperties-basic.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | 'jquery', 3 | './properties', 4 | './initialproperties' 5 | ], 6 | function ( $, props, initProps ) { 7 | 'use strict'; 8 | 9 | return { 10 | 11 | //definition: { 12 | // type: "items", 13 | // component: "accordion", 14 | // items: { 15 | // appearance: { 16 | // uses: "settings" 17 | // } 18 | // } 19 | //}, 20 | 21 | definition: { 22 | type: "items", 23 | component: "accordion", 24 | items: { 25 | dimensions: { 26 | uses: "dimensions" 27 | }, 28 | measures: { 29 | uses: "measures" 30 | }, 31 | sorting: { 32 | uses: "sorting" 33 | }, 34 | appearance: { 35 | uses: "settings" 36 | } 37 | } 38 | }, 39 | 40 | paint: function ( $element, layout ) { 41 | 42 | console.info( 'paint >> layout >> ', layout ); 43 | 44 | //$element.empty(); 45 | //var $msg = $( document.createElement( 'div' ) ); 46 | //$msg.html( 'Just demonstrating default behavior of the property panel"' ); 47 | //$element.append( $msg ); 48 | 49 | // Output values from the property panel 50 | 51 | $element.empty(); 52 | var $msg = $( document.createElement( 'div' ) ); 53 | var html = 'Property values:
'; 54 | html += 'Title: ' + layout.title + '
'; 55 | html += 'SubTitle: ' + layout.subtitle + '
'; 56 | $msg.html( html ); 57 | $element.append( $msg ); 58 | 59 | } 60 | }; 61 | 62 | } ); 63 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/src/exttut-06usingproperties-basic.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "06 Using Properties - Basic", 3 | "description" : "Basic example of using built-in properties.", 4 | "icon" : "extension", 5 | "type" : "visualization", 6 | "version": "@@version", 7 | "preview" : "06usingproperties-basic.png", 8 | "author": "Stefan Walther" 9 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/src/initialproperties.js: -------------------------------------------------------------------------------- 1 | /*global define*/ 2 | define( [], function () { 3 | 'use strict'; 4 | return { 5 | qHyperCubeDef: { 6 | qDimensions: [], 7 | qMeasures: [], 8 | qInitialDataFetch: [ 9 | { 10 | qWidth: 2, 11 | qHeight: 50 12 | } 13 | ] 14 | } 15 | }; 16 | } ); 17 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/06-Using-Properties-Basic/src/properties.js: -------------------------------------------------------------------------------- 1 | define( [], function () { 2 | 'use strict'; 3 | 4 | 5 | var dimensions = { 6 | uses: "dimensions" 7 | }; 8 | 9 | var measures = { 10 | uses: "measures" 11 | }; 12 | 13 | var sorting = { 14 | uses: "sorting" 15 | }; 16 | 17 | var addons = { 18 | uses: "addons" 19 | }; 20 | 21 | // Appearance Panel 22 | var appearancePanel = { 23 | uses: "settings" 24 | }; 25 | 26 | // Return values 27 | return { 28 | type: "items", 29 | component: "accordion", 30 | items: { 31 | dimensions: dimensions, 32 | measures: measures, 33 | sorting: sorting, 34 | // We'll use addons later on, by default not addons are define, 35 | // so the section will remain empty 36 | //addons: addons, 37 | appearance: appearancePanel 38 | 39 | } 40 | }; 41 | 42 | } ); 43 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # ========================= 5 | # Custom for Visual Studio 6 | # ========================= 7 | *.cs diff=csharp 8 | *.sln merge=union 9 | *.csproj merge=union 10 | *.vbproj merge=union 11 | *.fsproj merge=union 12 | *.dbproj merge=union 13 | 14 | # ========================= 15 | # Standard to msysgit 16 | # ========================= 17 | *.doc diff=astextplain 18 | *.DOC diff=astextplain 19 | *.docx diff=astextplain 20 | *.DOCX diff=astextplain 21 | *.dot diff=astextplain 22 | *.DOT diff=astextplain 23 | *.pdf diff=astextplain 24 | *.PDF diff=astextplain 25 | *.rtf diff=astextplain 26 | *.RTF diff=astextplain 27 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-qsextension": { 3 | "advancedMode": true, 4 | "extensionName": "07 Custom Properties", 5 | "extensionNameSafe": "07CustomProperties", 6 | "extensionType": "extension", 7 | "extensionNamespace": "exttut-", 8 | "extensionDescription": "Examples how to use custom properties.", 9 | "authorName": "Stefan Walther", 10 | "lessSupport": false, 11 | "license": "mit", 12 | "publishingYear": 2015, 13 | "creationDate": "2015-05-13", 14 | "licenceGenerated": "> \r\n> The MIT License (MIT)\r\n> \r\n> Copyright (c) 2015 Stefan Walther\r\n> \r\n> Permission is hereby granted, free of charge, to any person obtaining a copy\r\n> of this software and associated documentation files (the \"Software\"), to deal\r\n> in the Software without restriction, including without limitation the rights\r\n> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n> copies of the Software, and to permit persons to whom the Software is\r\n> furnished to do so, subject to the following conditions:\r\n> \r\n> The above copyright notice and this permission notice shall be included in all\r\n> copies or substantial portions of the Software.\r\n> \r\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n> SOFTWARE.\r\n> ", 15 | "localExtensionDir": "d:\\\\documents\\\\Qlik\\\\Sense\\\\Extensions" 16 | } 17 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## Version 0.1.0 4 | Date: 2015-05-19 5 | 6 | * Changes to reflect changes in chapter 07. 7 | 8 | ## Version 0.0.1 9 | Date: 2015-05-13 10 | 11 | * Initial Commit 12 | 13 | --- 14 | * Basic template and build system created using the [Yeoman Generator for Qlik Sense Extensions](https://github.com/stefanwalther/generator-qsExtension) 15 | 16 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/LICENSE.md: -------------------------------------------------------------------------------- 1 | **07 Custom Properties Qlik Sense Extension** is licensed under the "MIT" license: 2 | 3 | * [License](#license) 4 | * [External Libraries](#external libraries) 5 | 6 | --- 7 | 8 | ## License 9 | 10 | > 11 | > The MIT License (MIT) 12 | > 13 | > Copyright (c) 2015 Stefan Walther 14 | > 15 | > Permission is hereby granted, free of charge, to any person obtaining a copy 16 | > of this software and associated documentation files (the "Software"), to deal 17 | > in the Software without restriction, including without limitation the rights 18 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | > copies of the Software, and to permit persons to whom the Software is 20 | > furnished to do so, subject to the following conditions: 21 | > 22 | > The above copyright notice and this permission notice shall be included in all 23 | > copies or substantial portions of the Software. 24 | > 25 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | > SOFTWARE. 32 | > 33 | 34 | ## External Libraries 35 | 36 | These external libraries are used within this solution. Many thanks to the authors! 37 | 38 | **Library 1** 39 | * Name: 40 | * License: 41 | * Url: 42 | * Author: 43 | 44 | **Library 2** 45 | * Name: 46 | * License: 47 | * Url: 48 | * Author: 49 | 50 | --- 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/README.md: -------------------------------------------------------------------------------- 1 | # 07 Custom Properties 2 | > Examples how to use custom properties. 3 | 4 | ## Author 5 | 6 | **Stefan Walther** 7 | 8 | ## Change Log 9 | 10 | See [CHANGELOG.md](CHANGELOG.md) 11 | 12 | ## License & Copyright 13 | The software is made available "AS IS" without any warranty of any kind under the MIT License (MIT). 14 | 15 | See [Additional license information for this solution.](LICENSE.md) 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/build/exttut-07customproperties_dev.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/07-Custom-Properties/build/exttut-07customproperties_dev.zip -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/dist_dev/07customproperties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/07-Custom-Properties/dist_dev/07customproperties.png -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/dist_dev/exttut-07customproperties.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | /*'underscore',*/ 4 | './properties', 5 | './initialproperties', 6 | './lib/js/extensionUtils', 7 | 'text!./lib/css/style.css' 8 | ], 9 | function ($, /*_,*/ props, initProps, extensionUtils, cssContent) { 10 | 'use strict'; 11 | 12 | extensionUtils.addStyleToHeader(cssContent); 13 | 14 | console.log('Initializing - remove me'); 15 | 16 | return { 17 | 18 | definition: props, 19 | 20 | initialProperties: initProps, 21 | 22 | snapshot: { canTakeSnapshot: true }, 23 | 24 | resize : function( /*$element, layout*/ ) { 25 | //do nothing 26 | }, 27 | 28 | //clearSelectedValues : function($element) { 29 | // 30 | //}, 31 | 32 | 33 | // Angular Support (uncomment to use) 34 | //template: '', 35 | 36 | // Angular Controller 37 | //controller: ['$scope', function ($scope) { 38 | // 39 | //}], 40 | 41 | 42 | paint: function ( $element /*, layout*/ ) { 43 | 44 | /* 45 | console.groupCollapsed('Basic Objects'); 46 | console.info('$element:'); 47 | console.log($element); 48 | console.info('layout:'); 49 | console.log(layout); 50 | console.groupEnd(); 51 | */ 52 | 53 | $element.empty(); 54 | var $helloWorld = $(document.createElement('div')); 55 | $helloWorld.addClass('hello-world'); 56 | $helloWorld.html('Hello World from the extension "07 Custom Properties"'); 57 | $element.append($helloWorld); 58 | 59 | } 60 | }; 61 | 62 | }); 63 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/dist_dev/exttut-07customproperties.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "07 Custom Properties", 3 | "description" : "Examples how to use custom properties.", 4 | "icon" : "extension", 5 | "type" : "visualization", 6 | "version": "0.0.1", 7 | "preview" : "07customproperties.png", 8 | "author": "Stefan Walther" 9 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/dist_dev/initialproperties.js: -------------------------------------------------------------------------------- 1 | /*global define*/ 2 | define( [], function () { 3 | 'use strict'; 4 | return { 5 | qHyperCubeDef: { 6 | qDimensions: [], 7 | qMeasures: [], 8 | qInitialDataFetch: [ 9 | { 10 | qWidth: 2, 11 | qHeight: 50 12 | } 13 | ] 14 | } 15 | }; 16 | } ); 17 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/dist_dev/lib/css/style.css: -------------------------------------------------------------------------------- 1 | /* Styles for 07 Custom Properties */ 2 | 3 | /* Recommended pattern for styling your objects */ 4 | .qv-object-exttut-07customproperties .hello-world { 5 | color:#333; 6 | font-weight:bold; 7 | } 8 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/.jshintrc-release: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true, 75 | "_": true 76 | } 77 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/Gruntfile.clean.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-clean' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | force: true 11 | }, 12 | src: [ 13 | '../dist_dev/**/*.bak', 14 | '../dist_dev/**/*.less', 15 | '../dist_dev/**/*.tmpl' 16 | ], 17 | filter: 'isFile' 18 | }, 19 | release: { 20 | options: { 21 | force: true 22 | }, 23 | src: [ 24 | '../dist/**/*.bak', 25 | '../dist/**/*.less', 26 | '../dist/**/*.tmpl' 27 | ], 28 | filter: 'isFile' 29 | }, 30 | empty_dist_dev: { 31 | options: { 32 | force: true 33 | }, 34 | src: [ 35 | '../dist_dev/**/*' 36 | ] 37 | }, 38 | empty_dist: { 39 | options: { 40 | force: true 41 | }, 42 | src: [ 43 | '../dist/**/*' 44 | ] 45 | }, 46 | empty_desktop: { 47 | options: { 48 | force: true 49 | }, 50 | src: [ 51 | '<%=projectconfig.general.ExtensionNamespace%>/<%=projectconfig.general.ExtensionNameSafe%>/**/*' 52 | ] 53 | } 54 | }; 55 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/Gruntfile.cleanempty.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks('grunt-cleanempty'); 6 | return { 7 | 8 | options: { 9 | force: true 10 | }, 11 | all: { 12 | options: { 13 | files: false 14 | }, 15 | src: ['../dist/**/*'] 16 | } 17 | 18 | }; 19 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/Gruntfile.compress.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-compress' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_dev.zip' 11 | }, 12 | files: [ 13 | { 14 | expand: true, 15 | cwd: '../dist_dev/', 16 | src: ['**/*.*'], 17 | dest: '/' 18 | } 19 | ] 20 | }, 21 | release: { 22 | options: { 23 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_v<%=projectconfig.general.Version%>.zip' 24 | }, 25 | files: [ 26 | { 27 | expand: true, 28 | cwd: '../dist/', 29 | src: ['**/*.*'], 30 | dest: '/' 31 | } 32 | ] 33 | }, 34 | release_latest: { 35 | options: { 36 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_latest.zip' 37 | }, 38 | files: [ 39 | { 40 | expand: true, 41 | cwd: '../dist/', 42 | src: ['**/*.*'], 43 | dest: '/' 44 | } 45 | ] 46 | }, 47 | source: { 48 | options: { 49 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe%>_src_v<%=projectconfig.general.Version%>.zip' 50 | }, 51 | files: [ 52 | { 53 | expand: true, 54 | cwd: '../', 55 | src: ['src/**/*', 'grunt/**/*', '!grunt/node_modules/**/*'], 56 | dest: '/' 57 | } 58 | ] 59 | } 60 | }; 61 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/Gruntfile.copy.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-copy' ); 6 | return { 7 | options: { 8 | processContentExclude: ['**/*.{png,gif,jpg,ico,psd}'] 9 | }, 10 | copy_to_dist_dev: { 11 | expand: true, // allow dynamic building 12 | cwd: '../src/', // change base dir 13 | //src: ['**', '!docs/**'], // source files mask 14 | src: ['**'], 15 | dest: '../dist_dev/', // destination folder 16 | flatten: false // remove all unnecessary nesting 17 | }, 18 | copy_to_dist_release: { 19 | expand: true, // allow dynamic building 20 | cwd: '../src/', // change base dir 21 | //src: ['**', '!docs/**'], // source files mask 22 | src: ['**'], 23 | dest: '../dist/', // destination folder 24 | flatten: false // remove all unnecessary nesting 25 | }, 26 | copy_to_desktop_dev: { 27 | expand: true, 28 | cwd: '../dist_dev/', 29 | src: '**', 30 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 31 | }, 32 | copy_to_desktop_release: { 33 | expand: true, 34 | cwd: '../dist/', 35 | src: '**', 36 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 37 | } 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/Gruntfile.jshint.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-jshint' ); 6 | return { 7 | dev: { 8 | options: { 9 | jshintrc: ".jshintrc-dev", 10 | ignores: [] 11 | }, 12 | defaults: ["<%=projectconfig.jsSources.dev%>"] 13 | }, 14 | release: { 15 | options: { 16 | jshintrc: ".jshintrc-release", 17 | ignores: [] 18 | }, 19 | defaults: ["<%=projectconfig.jsSources.release%>"] 20 | } 21 | 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/Gruntfile.projectconfig.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | var YAML = require( 'yamljs' ); 3 | module.exports = function ( grunt ) { 4 | 'use strict'; 5 | return YAML.load( 'grunt-config.yml' ); 6 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/Gruntfile.uglify.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | /*jshint 3 | camelcase: false 4 | */ 5 | module.exports = function ( grunt ) { 6 | 'use strict'; 7 | 8 | grunt.loadNpmTasks( 'grunt-contrib-uglify' ); 9 | return { 10 | 11 | options: { 12 | mangle: '<%= projectconfig.release.uglify.mangle%>', 13 | beautify: '<%= projectconfig.release.uglify.beautify%>', 14 | preserveComments: '<%= projectconfig.release.uglify.preserveComments%>', 15 | compress: { 16 | drop_console: '<%= projectconfig.release.uglify.drop_console%>' 17 | } 18 | }, 19 | release: { 20 | files: [ 21 | { 22 | src: ['./../dist/**/*.js', '!./../dist/**/*.min.js'], 23 | dest: './../dist/', 24 | expand: true 25 | } 26 | ] 27 | } 28 | }; 29 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/gruntReplacements.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in both the dev and release 5 | # task 6 | # 7 | # In your code just use @@variable 8 | # ------------------------------------------------------------------- 9 | 10 | # You have to have at least one variable here 11 | dummy: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/gruntReplacements_dev.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the dev task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: true -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/gruntReplacements_release.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the release task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/grunt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Grunt-Deployment-07CustomProperties", 3 | "version": "0.0.1", 4 | "description": "Grunt tasks (dev + release) for the Qlik Sense extension 07 Custom Properties", 5 | "main": "gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "Qlik Sense Extension", 11 | "qliksense-visualization-extension", 12 | "Qlik Sense", 13 | "QlikSense", 14 | "Extension" 15 | ], 16 | "author": "Stefan Walther", 17 | "license": "MIT", 18 | "dependencies": { 19 | "grunt": "~0.4.5", 20 | "grunt-contrib-clean": "~0.6.0", 21 | "grunt-cleanempty": "~1.0.3", 22 | "grunt-contrib-compress": "~0.13.0", 23 | "grunt-contrib-copy": "~0.8.0", 24 | "grunt-contrib-jshint": "^0.11.0", 25 | "grunt-contrib-less": "~1.0.0", 26 | "grunt-replace": "~0.8.0", 27 | "grunt-contrib-uglify": "~0.8.0", 28 | "q": "^1.2.0", 29 | "winreg": "0.0.12", 30 | "async": "^0.9.0", 31 | "yamljs": "^0.2.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/src/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true 75 | } 76 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/src/07customproperties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/07-Custom-Properties/src/07customproperties.png -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/src/exttut-07customproperties.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | /*'underscore',*/ 4 | './properties', 5 | './initialproperties', 6 | './lib/js/extensionUtils', 7 | 'text!./lib/css/style.css' 8 | ], 9 | function ($, /*_,*/ props, initProps, extensionUtils, cssContent) { 10 | 'use strict'; 11 | 12 | extensionUtils.addStyleToHeader(cssContent); 13 | 14 | console.log('Initializing - remove me'); 15 | 16 | return { 17 | 18 | definition: props, 19 | 20 | initialProperties: initProps, 21 | 22 | snapshot: { canTakeSnapshot: true }, 23 | 24 | resize : function( /*$element, layout*/ ) { 25 | //do nothing 26 | }, 27 | 28 | //clearSelectedValues : function($element) { 29 | // 30 | //}, 31 | 32 | 33 | // Angular Support (uncomment to use) 34 | //template: '', 35 | 36 | // Angular Controller 37 | //controller: ['$scope', function ($scope) { 38 | // 39 | //}], 40 | 41 | 42 | paint: function ( $element /*, layout*/ ) { 43 | 44 | /* 45 | console.groupCollapsed('Basic Objects'); 46 | console.info('$element:'); 47 | console.log($element); 48 | console.info('layout:'); 49 | console.log(layout); 50 | console.groupEnd(); 51 | */ 52 | 53 | $element.empty(); 54 | var $helloWorld = $(document.createElement('div')); 55 | $helloWorld.addClass('hello-world'); 56 | $helloWorld.html('Hello World from the extension "07 Custom Properties"'); 57 | $element.append($helloWorld); 58 | 59 | } 60 | }; 61 | 62 | }); 63 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/src/exttut-07customproperties.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "07 Custom Properties", 3 | "description" : "Examples how to use custom properties.", 4 | "icon" : "extension", 5 | "type" : "visualization", 6 | "version": "@@version", 7 | "preview" : "07customproperties.png", 8 | "author": "Stefan Walther" 9 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/src/initialproperties.js: -------------------------------------------------------------------------------- 1 | /*global define*/ 2 | define( [], function () { 3 | 'use strict'; 4 | return { 5 | qHyperCubeDef: { 6 | qDimensions: [], 7 | qMeasures: [], 8 | qInitialDataFetch: [ 9 | { 10 | qWidth: 2, 11 | qHeight: 50 12 | } 13 | ] 14 | } 15 | }; 16 | } ); 17 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/07-Custom-Properties/src/lib/css/style.css: -------------------------------------------------------------------------------- 1 | /* Styles for 07 Custom Properties */ 2 | 3 | /* Recommended pattern for styling your objects */ 4 | .qv-object-exttut-07customproperties .hello-world { 5 | color:#333; 6 | font-weight:bold; 7 | } 8 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # ========================= 5 | # Custom for Visual Studio 6 | # ========================= 7 | *.cs diff=csharp 8 | *.sln merge=union 9 | *.csproj merge=union 10 | *.vbproj merge=union 11 | *.fsproj merge=union 12 | *.dbproj merge=union 13 | 14 | # ========================= 15 | # Standard to msysgit 16 | # ========================= 17 | *.doc diff=astextplain 18 | *.DOC diff=astextplain 19 | *.docx diff=astextplain 20 | *.DOCX diff=astextplain 21 | *.dot diff=astextplain 22 | *.DOT diff=astextplain 23 | *.pdf diff=astextplain 24 | *.PDF diff=astextplain 25 | *.rtf diff=astextplain 26 | *.RTF diff=astextplain 27 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-qsextension": { 3 | "advancedMode": true, 4 | "extensionName": "08 - Hello Data", 5 | "extensionNameSafe": "08-HelloData", 6 | "extensionType": "extension", 7 | "extensionNamespace": "exttut-", 8 | "extensionDescription": "Examples how to use data in visualization extensions.", 9 | "authorName": "Stefan Walther", 10 | "lessSupport": true, 11 | "license": "mit", 12 | "publishingYear": 2015, 13 | "creationDate": "2015-05-18", 14 | "licenceGenerated": "> \r\n> The MIT License (MIT)\r\n> \r\n> Copyright (c) 2015 Stefan Walther\r\n> \r\n> Permission is hereby granted, free of charge, to any person obtaining a copy\r\n> of this software and associated documentation files (the \"Software\"), to deal\r\n> in the Software without restriction, including without limitation the rights\r\n> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n> copies of the Software, and to permit persons to whom the Software is\r\n> furnished to do so, subject to the following conditions:\r\n> \r\n> The above copyright notice and this permission notice shall be included in all\r\n> copies or substantial portions of the Software.\r\n> \r\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n> SOFTWARE.\r\n> ", 15 | "localExtensionDir": "d:\\\\documents\\\\Qlik\\\\Sense\\\\Extensions" 16 | } 17 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## Version 0.0.1 4 | Date: 2015-05-18 5 | 6 | * Initial Commit 7 | 8 | --- 9 | * Basic template and build system created using the [Yeoman Generator for Qlik Sense Extensions](https://github.com/stefanwalther/generator-qsExtension) 10 | 11 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/LICENSE.md: -------------------------------------------------------------------------------- 1 | **08 - Hello Data Qlik Sense Extension** is licensed under the "MIT" license: 2 | 3 | * [License](#license) 4 | * [External Libraries](#external libraries) 5 | 6 | --- 7 | 8 | ## License 9 | 10 | > 11 | > The MIT License (MIT) 12 | > 13 | > Copyright (c) 2015 Stefan Walther 14 | > 15 | > Permission is hereby granted, free of charge, to any person obtaining a copy 16 | > of this software and associated documentation files (the "Software"), to deal 17 | > in the Software without restriction, including without limitation the rights 18 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | > copies of the Software, and to permit persons to whom the Software is 20 | > furnished to do so, subject to the following conditions: 21 | > 22 | > The above copyright notice and this permission notice shall be included in all 23 | > copies or substantial portions of the Software. 24 | > 25 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | > SOFTWARE. 32 | > 33 | 34 | ## External Libraries 35 | 36 | These external libraries are used within this solution. Many thanks to the authors! 37 | 38 | **Library 1** 39 | * Name: 40 | * License: 41 | * Url: 42 | * Author: 43 | 44 | **Library 2** 45 | * Name: 46 | * License: 47 | * Url: 48 | * Author: 49 | 50 | --- 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/README.md: -------------------------------------------------------------------------------- 1 | # 08 - Hello Data 2 | > Examples how to use data in visualization extensions. 3 | 4 | ## Purpose and Description 5 | 6 | ## Screenshots 7 | 8 | ## Installation 9 | 10 | 1. Download the latest version 11 | 2. Qlik Sense Desktop 12 | * To install, copy all files in the .zip file to folder "C:\Users\[%Username%]\Documents\Qlik\Sense\Extensions\08-HelloData" 13 | 3. Qlik Sense Server 14 | * See instructions [how to import an extension on Qlik Sense Server](http://help.qlik.com/sense/en-us/developer/#../Subsystems/Workbench/Content/BuildingExtensions/HowTos/deploy-extensions.htm) 15 | 16 | ## Configuration 17 | 18 | ## Contributing 19 | Contributing to this project is welcome. The process to do so is outlined below: 20 | 21 | 1. Create a fork of the project 22 | 2. Work on whatever bug or feature you wish 23 | 3. Create a pull request (PR) 24 | 25 | I cannot guarantee that I will merge all PRs but I will evaluate them all. 26 | 27 | ## Author 28 | 29 | **Stefan Walther** 30 | * http://www.yourwebsite.com 31 | * http://github.com/yourname 32 | 33 | 34 | ## Change Log 35 | 36 | See [CHANGELOG.md](CHANGELOG.md) 37 | 38 | ## License & Copyright 39 | The software is made available "AS IS" without any warranty of any kind under the MIT License (MIT). 40 | 41 | See [Additional license information for this solution.](LICENSE.md) 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/.jshintrc-release: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true, 75 | "_": true 76 | } 77 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/Gruntfile.clean.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-clean' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | force: true 11 | }, 12 | src: [ 13 | '../dist_dev/**/*.bak', 14 | '../dist_dev/**/*.less', 15 | '../dist_dev/**/*.tmpl' 16 | ], 17 | filter: 'isFile' 18 | }, 19 | release: { 20 | options: { 21 | force: true 22 | }, 23 | src: [ 24 | '../dist/**/*.bak', 25 | '../dist/**/*.less', 26 | '../dist/**/*.tmpl' 27 | ], 28 | filter: 'isFile' 29 | }, 30 | empty_dist_dev: { 31 | options: { 32 | force: true 33 | }, 34 | src: [ 35 | '../dist_dev/**/*' 36 | ] 37 | }, 38 | empty_dist: { 39 | options: { 40 | force: true 41 | }, 42 | src: [ 43 | '../dist/**/*' 44 | ] 45 | }, 46 | empty_desktop: { 47 | options: { 48 | force: true 49 | }, 50 | src: [ 51 | '<%=projectconfig.general.ExtensionNamespace%>/<%=projectconfig.general.ExtensionNameSafe%>/**/*' 52 | ] 53 | } 54 | }; 55 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/Gruntfile.cleanempty.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks('grunt-cleanempty'); 6 | return { 7 | 8 | options: { 9 | force: true 10 | }, 11 | all: { 12 | options: { 13 | files: false 14 | }, 15 | src: ['../dist/**/*'] 16 | } 17 | 18 | }; 19 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/Gruntfile.compress.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-compress' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_dev.zip' 11 | }, 12 | files: [ 13 | { 14 | expand: true, 15 | cwd: '../dist_dev/', 16 | src: ['**/*.*'], 17 | dest: '/' 18 | } 19 | ] 20 | }, 21 | release: { 22 | options: { 23 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_v<%=projectconfig.general.Version%>.zip' 24 | }, 25 | files: [ 26 | { 27 | expand: true, 28 | cwd: '../dist/', 29 | src: ['**/*.*'], 30 | dest: '/' 31 | } 32 | ] 33 | }, 34 | release_latest: { 35 | options: { 36 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_latest.zip' 37 | }, 38 | files: [ 39 | { 40 | expand: true, 41 | cwd: '../dist/', 42 | src: ['**/*.*'], 43 | dest: '/' 44 | } 45 | ] 46 | }, 47 | source: { 48 | options: { 49 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe%>_src_v<%=projectconfig.general.Version%>.zip' 50 | }, 51 | files: [ 52 | { 53 | expand: true, 54 | cwd: '../', 55 | src: ['src/**/*', 'grunt/**/*', '!grunt/node_modules/**/*'], 56 | dest: '/' 57 | } 58 | ] 59 | } 60 | }; 61 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/Gruntfile.copy.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-copy' ); 6 | return { 7 | options: { 8 | processContentExclude: ['**/*.{png,gif,jpg,ico,psd}'] 9 | }, 10 | copy_to_dist_dev: { 11 | expand: true, // allow dynamic building 12 | cwd: '../src/', // change base dir 13 | //src: ['**', '!docs/**'], // source files mask 14 | src: ['**'], 15 | dest: '../dist_dev/', // destination folder 16 | flatten: false // remove all unnecessary nesting 17 | }, 18 | copy_to_dist_release: { 19 | expand: true, // allow dynamic building 20 | cwd: '../src/', // change base dir 21 | //src: ['**', '!docs/**'], // source files mask 22 | src: ['**'], 23 | dest: '../dist/', // destination folder 24 | flatten: false // remove all unnecessary nesting 25 | }, 26 | copy_to_desktop_dev: { 27 | expand: true, 28 | cwd: '../dist_dev/', 29 | src: '**', 30 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 31 | }, 32 | copy_to_desktop_release: { 33 | expand: true, 34 | cwd: '../dist/', 35 | src: '**', 36 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 37 | } 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/Gruntfile.jshint.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-jshint' ); 6 | return { 7 | dev: { 8 | options: { 9 | jshintrc: ".jshintrc-dev", 10 | ignores: [] 11 | }, 12 | defaults: ["<%=projectconfig.jsSources.dev%>"] 13 | }, 14 | release: { 15 | options: { 16 | jshintrc: ".jshintrc-release", 17 | ignores: [] 18 | }, 19 | defaults: ["<%=projectconfig.jsSources.release%>"] 20 | } 21 | 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/Gruntfile.less.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-less' ); 6 | return { 7 | 8 | // If used converts all the objects in place (mainly used for debugging purposes) 9 | allInPlace_dev: { 10 | options: { 11 | compress: false, 12 | yuicompress: false, 13 | optimization: 2, 14 | cleancss: false, 15 | paths: ['../dist_dev'] 16 | }, 17 | files: [{ 18 | expand: true, 19 | cwd: "../dist_dev", 20 | src: ["**/*.less"], 21 | ext: ".css", 22 | dest: "../dist_dev" 23 | }] 24 | }, 25 | dev: { 26 | options: { 27 | compress: '<%= projectconfig.dev.less.lessCompress%>', 28 | yuicompress: '<%= projectconfig.dev.less.lessYuiCompress%>', 29 | optimization: parseInt( 'projectconfig.dev.less.lessOptimization' ), 30 | cleancss: '<%= projectconfig.dev.less.lessCleanCss%>' 31 | }, 32 | files: { 33 | "../dist_dev/lib/css/style.css": "../src/lib/less/_root.less" 34 | } 35 | }, 36 | release: { 37 | options: { 38 | compress: '<%= projectconfig.release.less.lessCompress%>', 39 | yuicompress: '<%= projectconfig.release.less.lessYuiCompress%>', 40 | optimization: parseInt( 'projectconfig.release.less.lessOptimization' ), 41 | cleancss: '<%= projectconfig.release.less.lessCleanCss%>' 42 | }, 43 | files: { 44 | "../dist/lib/css/style.css": "../src/lib/less/_root.less" 45 | } 46 | } 47 | }; 48 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/Gruntfile.projectconfig.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | var YAML = require( 'yamljs' ); 3 | module.exports = function ( grunt ) { 4 | 'use strict'; 5 | return YAML.load( 'grunt-config.yml' ); 6 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/Gruntfile.uglify.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | /*jshint 3 | camelcase: false 4 | */ 5 | module.exports = function ( grunt ) { 6 | 'use strict'; 7 | 8 | grunt.loadNpmTasks( 'grunt-contrib-uglify' ); 9 | return { 10 | 11 | options: { 12 | mangle: '<%= projectconfig.release.uglify.mangle%>', 13 | beautify: '<%= projectconfig.release.uglify.beautify%>', 14 | preserveComments: '<%= projectconfig.release.uglify.preserveComments%>', 15 | compress: { 16 | drop_console: '<%= projectconfig.release.uglify.drop_console%>' 17 | } 18 | }, 19 | release: { 20 | files: [ 21 | { 22 | src: ['./../dist/**/*.js', '!./../dist/**/*.min.js'], 23 | dest: './../dist/', 24 | expand: true 25 | } 26 | ] 27 | } 28 | }; 29 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/gruntReplacements.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in both the dev and release 5 | # task 6 | # 7 | # In your code just use @@variable 8 | # ------------------------------------------------------------------- 9 | 10 | # You have to have at least one variable here 11 | dummy: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/gruntReplacements_dev.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the dev task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: true -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/gruntReplacements_release.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the release task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/grunt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Grunt-Deployment-08-HelloData", 3 | "version": "0.0.1", 4 | "description": "Grunt tasks (dev + release) for the Qlik Sense extension 08 - Hello Data", 5 | "main": "gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "Qlik Sense Extension", 11 | "qliksense-visualization-extension", 12 | "Qlik Sense", 13 | "QlikSense", 14 | "Extension" 15 | ], 16 | "author": "Stefan Walther", 17 | "license": "MIT", 18 | "dependencies": { 19 | "grunt": "~0.4.5", 20 | "grunt-contrib-clean": "~0.6.0", 21 | "grunt-cleanempty": "~1.0.3", 22 | "grunt-contrib-compress": "~0.13.0", 23 | "grunt-contrib-copy": "~0.8.0", 24 | "grunt-contrib-jshint": "^0.11.0", 25 | "grunt-contrib-less": "~1.0.0", 26 | "grunt-replace": "~0.8.0", 27 | "grunt-contrib-uglify": "~0.8.0", 28 | "q": "^1.2.0", 29 | "winreg": "0.0.12", 30 | "async": "^0.9.0", 31 | "yamljs": "^0.2.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/src/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true 75 | } 76 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/src/08-hellodata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/08-Hello-Data/src/08-hellodata.png -------------------------------------------------------------------------------- /Chapters-Source/part-01/08-Hello-Data/src/exttut-08-hellodata.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "08 - Hello Data", 3 | "description" : "Examples how to use data in visualization extensions.", 4 | "icon" : "extension", 5 | "type" : "visualization", 6 | "version": "@@version", 7 | "preview" : "08-hellodata.png", 8 | "author": "Stefan Walther" 9 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # ========================= 5 | # Custom for Visual Studio 6 | # ========================= 7 | *.cs diff=csharp 8 | *.sln merge=union 9 | *.csproj merge=union 10 | *.vbproj merge=union 11 | *.fsproj merge=union 12 | *.dbproj merge=union 13 | 14 | # ========================= 15 | # Standard to msysgit 16 | # ========================= 17 | *.doc diff=astextplain 18 | *.DOC diff=astextplain 19 | *.docx diff=astextplain 20 | *.DOCX diff=astextplain 21 | *.dot diff=astextplain 22 | *.DOT diff=astextplain 23 | *.pdf diff=astextplain 24 | *.PDF diff=astextplain 25 | *.rtf diff=astextplain 26 | *.RTF diff=astextplain 27 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/CHANGELOG.yml: -------------------------------------------------------------------------------- 1 | v0.0.1: 2 | date: "2015-07-03" 3 | new: 4 | - Initial Commit 5 | enhancements: 6 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/LICENSE.md: -------------------------------------------------------------------------------- 1 | **09 - Loading Resources Qlik Sense Extension** is licensed under the "MIT" license: 2 | 3 | * [License](#license) 4 | * [External Libraries](#external libraries) 5 | 6 | --- 7 | 8 | ## License 9 | 10 | > 11 | > The MIT License (MIT) 12 | > 13 | > Copyright (c) 2015 Stefan Walther 14 | > 15 | > Permission is hereby granted, free of charge, to any person obtaining a copy 16 | > of this software and associated documentation files (the "Software"), to deal 17 | > in the Software without restriction, including without limitation the rights 18 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | > copies of the Software, and to permit persons to whom the Software is 20 | > furnished to do so, subject to the following conditions: 21 | > 22 | > The above copyright notice and this permission notice shall be included in all 23 | > copies or substantial portions of the Software. 24 | > 25 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | > SOFTWARE. 32 | > 33 | 34 | ## External Libraries 35 | 36 | These external libraries are used within this solution. Many thanks to the authors! 37 | 38 | **Library 1** 39 | * Name: 40 | * License: 41 | * Url: 42 | * Author: 43 | 44 | **Library 2** 45 | * Name: 46 | * License: 47 | * Url: 48 | * Author: 49 | 50 | --- 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/README.md: -------------------------------------------------------------------------------- 1 | # 09 - Loading Resources 2 | > Examples how to load several kinds of resources in a Qlik Sense visualization extension. 3 | 4 | ## Purpose and Description 5 | 6 | ## Screenshots 7 | 8 | ## Installation 9 | 10 | 1. Download the latest version 11 | 2. Qlik Sense Desktop 12 | * To install, copy all files in the .zip file to folder "C:\Users\[%Username%]\Documents\Qlik\Sense\Extensions\09-LoadingResources" 13 | 3. Qlik Sense Server 14 | * See instructions [how to import an extension on Qlik Sense Server](http://help.qlik.com/sense/en-us/developer/#../Subsystems/Workbench/Content/BuildingExtensions/HowTos/deploy-extensions.htm) 15 | 16 | ## Configuration 17 | 18 | ## Contributing 19 | Contributing to this project is welcome. The process to do so is outlined below: 20 | 21 | 1. Create a fork of the project 22 | 2. Work on whatever bug or feature you wish 23 | 3. Create a pull request (PR) 24 | 25 | I cannot guarantee that I will merge all PRs but I will evaluate them all. 26 | 27 | ## Author 28 | 29 | **Stefan Walther** 30 | * http://www.yourwebsite.com 31 | * http://github.com/yourname 32 | 33 | 34 | ## Change Log 35 | 36 | See [CHANGELOG](CHANGELOG.yml) 37 | 38 | ## License & Copyright 39 | The software is made available "AS IS" without any warranty of any kind under the MIT License (MIT). 40 | 41 | See [Additional license information for this solution.](LICENSE.md) 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/dist_dev/09-loadingresources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/09-Loading-Resources/dist_dev/09-loadingresources.png -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/dist_dev/exttut-09-loadingresources.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | './lib/js/extensionUtils', 4 | 'text!./lib/css/style.css' 5 | ], 6 | function ($, extensionUtils, cssContent) { 7 | 'use strict'; 8 | 9 | extensionUtils.addStyleToHeader(cssContent); 10 | 11 | console.log('Initializing - remove me'); 12 | 13 | return { 14 | 15 | paint: function ( $element /*, layout*/ ) { 16 | 17 | $element.empty(); 18 | $element.append(''); 19 | 20 | } 21 | }; 22 | 23 | }); 24 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/dist_dev/exttut-09-loadingresources.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "09 - Loading Resources", 3 | "description" : "Examples how to load several kinds of resources in a Qlik Sense visualization extension.", 4 | "icon" : "extension", 5 | "type" : "visualization", 6 | "version": "0.0.1", 7 | "preview" : "09-loadingresources.png", 8 | "author": "Stefan Walther" 9 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/dist_dev/lib/css/style.css: -------------------------------------------------------------------------------- 1 | /* Styles for 09 - Loading Resources */ 2 | 3 | /* Recommended pattern for styling your objects */ 4 | .qv-object-exttut-09-loadingresources .hello-world { 5 | color:#333; 6 | font-weight:bold; 7 | } 8 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/dist_dev/lib/images/pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/09-Loading-Resources/dist_dev/lib/images/pic.png -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/.jshintrc-release: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true, 75 | "_": true 76 | } 77 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/Gruntfile.clean.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-clean' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | force: true 11 | }, 12 | src: [ 13 | '../dist_dev/**/*.bak', 14 | '../dist_dev/**/*.less', 15 | '../dist_dev/**/*.tmpl' 16 | ], 17 | filter: 'isFile' 18 | }, 19 | release: { 20 | options: { 21 | force: true 22 | }, 23 | src: [ 24 | '../dist/**/*.bak', 25 | '../dist/**/*.less', 26 | '../dist/**/*.tmpl' 27 | ], 28 | filter: 'isFile' 29 | }, 30 | empty_dist_dev: { 31 | options: { 32 | force: true 33 | }, 34 | src: [ 35 | '../dist_dev/**/*' 36 | ] 37 | }, 38 | empty_dist: { 39 | options: { 40 | force: true 41 | }, 42 | src: [ 43 | '../dist/**/*' 44 | ] 45 | }, 46 | empty_desktop: { 47 | options: { 48 | force: true 49 | }, 50 | src: [ 51 | '<%=projectconfig.general.ExtensionNamespace%>/<%=projectconfig.general.ExtensionNameSafe%>/**/*' 52 | ] 53 | } 54 | }; 55 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/Gruntfile.cleanempty.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks('grunt-cleanempty'); 6 | return { 7 | 8 | options: { 9 | force: true 10 | }, 11 | all: { 12 | options: { 13 | files: false 14 | }, 15 | src: ['../dist/**/*'] 16 | } 17 | 18 | }; 19 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/Gruntfile.compress.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-compress' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_dev.zip' 11 | }, 12 | files: [ 13 | { 14 | expand: true, 15 | cwd: '../dist_dev/', 16 | src: ['**/*.*'], 17 | dest: '/' 18 | } 19 | ] 20 | }, 21 | release: { 22 | options: { 23 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_v<%=projectconfig.general.Version%>.zip' 24 | }, 25 | files: [ 26 | { 27 | expand: true, 28 | cwd: '../dist/', 29 | src: ['**/*.*'], 30 | dest: '/' 31 | } 32 | ] 33 | }, 34 | release_latest: { 35 | options: { 36 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_latest.zip' 37 | }, 38 | files: [ 39 | { 40 | expand: true, 41 | cwd: '../dist/', 42 | src: ['**/*.*'], 43 | dest: '/' 44 | } 45 | ] 46 | }, 47 | source: { 48 | options: { 49 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe%>_src_v<%=projectconfig.general.Version%>.zip' 50 | }, 51 | files: [ 52 | { 53 | expand: true, 54 | cwd: '../', 55 | src: ['src/**/*', 'grunt/**/*', '!grunt/node_modules/**/*'], 56 | dest: '/' 57 | } 58 | ] 59 | } 60 | }; 61 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/Gruntfile.copy.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-copy' ); 6 | return { 7 | options: { 8 | processContentExclude: ['**/*.{png,gif,jpg,ico,psd}'] 9 | }, 10 | copy_to_dist_dev: { 11 | expand: true, // allow dynamic building 12 | cwd: '../src/', // change base dir 13 | //src: ['**', '!docs/**'], // source files mask 14 | src: ['**'], 15 | dest: '../dist_dev/', // destination folder 16 | flatten: false // remove all unnecessary nesting 17 | }, 18 | copy_to_dist_release: { 19 | expand: true, // allow dynamic building 20 | cwd: '../src/', // change base dir 21 | //src: ['**', '!docs/**'], // source files mask 22 | src: ['**'], 23 | dest: '../dist/', // destination folder 24 | flatten: false // remove all unnecessary nesting 25 | }, 26 | copy_to_desktop_dev: { 27 | expand: true, 28 | cwd: '../dist_dev/', 29 | src: '**', 30 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 31 | }, 32 | copy_to_desktop_release: { 33 | expand: true, 34 | cwd: '../dist/', 35 | src: '**', 36 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 37 | } 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/Gruntfile.jshint.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-jshint' ); 6 | return { 7 | dev: { 8 | options: { 9 | jshintrc: ".jshintrc-dev", 10 | ignores: [] 11 | }, 12 | defaults: ["<%=projectconfig.jsSources.dev%>"] 13 | }, 14 | release: { 15 | options: { 16 | jshintrc: ".jshintrc-release", 17 | ignores: [] 18 | }, 19 | defaults: ["<%=projectconfig.jsSources.release%>"] 20 | } 21 | 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/Gruntfile.projectconfig.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | var YAML = require( 'yamljs' ); 3 | module.exports = function ( grunt ) { 4 | 'use strict'; 5 | return YAML.load( 'grunt-config.yml' ); 6 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/Gruntfile.uglify.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | /*jshint 3 | camelcase: false 4 | */ 5 | module.exports = function ( grunt ) { 6 | 'use strict'; 7 | 8 | grunt.loadNpmTasks( 'grunt-contrib-uglify' ); 9 | return { 10 | 11 | options: { 12 | mangle: '<%= projectconfig.release.uglify.mangle%>', 13 | beautify: '<%= projectconfig.release.uglify.beautify%>', 14 | preserveComments: '<%= projectconfig.release.uglify.preserveComments%>', 15 | compress: { 16 | drop_console: '<%= projectconfig.release.uglify.drop_console%>' 17 | } 18 | }, 19 | release: { 20 | files: [ 21 | { 22 | src: ['./../dist/**/*.js', '!./../dist/**/*.min.js'], 23 | dest: './../dist/', 24 | expand: true 25 | } 26 | ] 27 | } 28 | }; 29 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/gruntReplacements.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in both the dev and release 5 | # task 6 | # 7 | # In your code just use @@variable 8 | # ------------------------------------------------------------------- 9 | 10 | # You have to have at least one variable here 11 | dummy: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/gruntReplacements_dev.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the dev task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: true -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/gruntReplacements_release.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the release task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/grunt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Grunt-Deployment-09-LoadingResources", 3 | "version": "0.0.1", 4 | "description": "Grunt tasks (dev + release) for the Qlik Sense extension 09 - Loading Resources", 5 | "main": "gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "Qlik Sense Extension", 11 | "qliksense-visualization-extension", 12 | "Qlik Sense", 13 | "QlikSense", 14 | "Extension" 15 | ], 16 | "author": "Stefan Walther", 17 | "license": "MIT", 18 | "dependencies": { 19 | "grunt": "~0.4.5", 20 | "grunt-contrib-clean": "~0.6.0", 21 | "grunt-cleanempty": "~1.0.3", 22 | "grunt-contrib-compress": "~0.13.0", 23 | "grunt-contrib-copy": "~0.8.0", 24 | "grunt-contrib-jshint": "^0.11.0", 25 | "grunt-contrib-less": "~1.0.0", 26 | "grunt-replace": "~0.8.0", 27 | "grunt-contrib-uglify": "~0.8.0", 28 | "q": "^1.2.0", 29 | "winreg": "0.0.12", 30 | "async": "^0.9.0", 31 | "yamljs": "^0.2.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/src/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true 75 | } 76 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/src/09-loadingresources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/09-Loading-Resources/src/09-loadingresources.png -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/src/exttut-09-loadingresources.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | './lib/js/extensionUtils', 4 | 'text!./lib/css/style.css' 5 | ], 6 | function ($, extensionUtils, cssContent) { 7 | 'use strict'; 8 | 9 | extensionUtils.addStyleToHeader(cssContent); 10 | 11 | console.log('Initializing - remove me'); 12 | 13 | return { 14 | 15 | paint: function ( $element /*, layout*/ ) { 16 | 17 | $element.empty(); 18 | $element.append(''); 19 | 20 | } 21 | }; 22 | 23 | }); 24 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/src/exttut-09-loadingresources.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "09 - Loading Resources", 3 | "description" : "Examples how to load several kinds of resources in a Qlik Sense visualization extension.", 4 | "icon" : "extension", 5 | "type" : "visualization", 6 | "version": "@@version", 7 | "preview" : "09-loadingresources.png", 8 | "author": "Stefan Walther" 9 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/src/lib/css/style.css: -------------------------------------------------------------------------------- 1 | /* Styles for 09 - Loading Resources */ 2 | 3 | /* Recommended pattern for styling your objects */ 4 | .qv-object-exttut-09-loadingresources .hello-world { 5 | color:#333; 6 | font-weight:bold; 7 | } 8 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/09-Loading-Resources/src/lib/images/pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/09-Loading-Resources/src/lib/images/pic.png -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # ========================= 5 | # Custom for Visual Studio 6 | # ========================= 7 | *.cs diff=csharp 8 | *.sln merge=union 9 | *.csproj merge=union 10 | *.vbproj merge=union 11 | *.fsproj merge=union 12 | *.dbproj merge=union 13 | 14 | # ========================= 15 | # Standard to msysgit 16 | # ========================= 17 | *.doc diff=astextplain 18 | *.DOC diff=astextplain 19 | *.docx diff=astextplain 20 | *.DOCX diff=astextplain 21 | *.dot diff=astextplain 22 | *.DOT diff=astextplain 23 | *.pdf diff=astextplain 24 | *.PDF diff=astextplain 25 | *.rtf diff=astextplain 26 | *.RTF diff=astextplain 27 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/CHANGELOG.yml: -------------------------------------------------------------------------------- 1 | v0.0.1: 2 | date: "2015-07-03" 3 | new: 4 | - Initial Commit 5 | enhancements: 6 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/LICENSE.md: -------------------------------------------------------------------------------- 1 | **10-Hello-Data-Performancetest Qlik Sense Extension** is licensed under the "MIT" license: 2 | 3 | * [License](#license) 4 | * [External Libraries](#external libraries) 5 | 6 | --- 7 | 8 | ## License 9 | 10 | > 11 | > The MIT License (MIT) 12 | > 13 | > Copyright (c) 2015 Stefan Walther 14 | > 15 | > Permission is hereby granted, free of charge, to any person obtaining a copy 16 | > of this software and associated documentation files (the "Software"), to deal 17 | > in the Software without restriction, including without limitation the rights 18 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | > copies of the Software, and to permit persons to whom the Software is 20 | > furnished to do so, subject to the following conditions: 21 | > 22 | > The above copyright notice and this permission notice shall be included in all 23 | > copies or substantial portions of the Software. 24 | > 25 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | > SOFTWARE. 32 | > 33 | 34 | ## External Libraries 35 | 36 | These external libraries are used within this solution. Many thanks to the authors! 37 | 38 | **Library 1** 39 | * Name: 40 | * License: 41 | * Url: 42 | * Author: 43 | 44 | **Library 2** 45 | * Name: 46 | * License: 47 | * Url: 48 | * Author: 49 | 50 | --- 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/README.md: -------------------------------------------------------------------------------- 1 | # 10-Hello-Data-Performancetest 2 | > Comparing performance between html injection and dom object creation. 3 | 4 | ## Purpose and Description 5 | 6 | ## Screenshots 7 | 8 | ## Installation 9 | 10 | 1. Download the latest version 11 | 2. Qlik Sense Desktop 12 | * To install, copy all files in the .zip file to folder "C:\Users\[%Username%]\Documents\Qlik\Sense\Extensions\10-Hello-Data-Performancetest" 13 | 3. Qlik Sense Server 14 | * See instructions [how to import an extension on Qlik Sense Server](http://help.qlik.com/sense/en-us/developer/#../Subsystems/Workbench/Content/BuildingExtensions/HowTos/deploy-extensions.htm) 15 | 16 | ## Configuration 17 | 18 | ## Contributing 19 | Contributing to this project is welcome. The process to do so is outlined below: 20 | 21 | 1. Create a fork of the project 22 | 2. Work on whatever bug or feature you wish 23 | 3. Create a pull request (PR) 24 | 25 | I cannot guarantee that I will merge all PRs but I will evaluate them all. 26 | 27 | ## Author 28 | 29 | **Stefan Walther** 30 | * http://www.yourwebsite.com 31 | * http://github.com/yourname 32 | 33 | 34 | ## Change Log 35 | 36 | See [CHANGELOG](CHANGELOG.yml) 37 | 38 | ## License & Copyright 39 | The software is made available "AS IS" without any warranty of any kind under the MIT License (MIT). 40 | 41 | See [Additional license information for this solution.](LICENSE.md) 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/.jshintrc-release: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true, 75 | "_": true 76 | } 77 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/Gruntfile.clean.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-clean' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | force: true 11 | }, 12 | src: [ 13 | '../dist_dev/**/*.bak', 14 | '../dist_dev/**/*.less', 15 | '../dist_dev/**/*.tmpl' 16 | ], 17 | filter: 'isFile' 18 | }, 19 | release: { 20 | options: { 21 | force: true 22 | }, 23 | src: [ 24 | '../dist/**/*.bak', 25 | '../dist/**/*.less', 26 | '../dist/**/*.tmpl' 27 | ], 28 | filter: 'isFile' 29 | }, 30 | empty_dist_dev: { 31 | options: { 32 | force: true 33 | }, 34 | src: [ 35 | '../dist_dev/**/*' 36 | ] 37 | }, 38 | empty_dist: { 39 | options: { 40 | force: true 41 | }, 42 | src: [ 43 | '../dist/**/*' 44 | ] 45 | }, 46 | empty_desktop: { 47 | options: { 48 | force: true 49 | }, 50 | src: [ 51 | '<%=projectconfig.general.ExtensionNamespace%>/<%=projectconfig.general.ExtensionNameSafe%>/**/*' 52 | ] 53 | } 54 | }; 55 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/Gruntfile.cleanempty.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks('grunt-cleanempty'); 6 | return { 7 | 8 | options: { 9 | force: true 10 | }, 11 | all: { 12 | options: { 13 | files: false 14 | }, 15 | src: ['../dist/**/*'] 16 | } 17 | 18 | }; 19 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/Gruntfile.compress.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-compress' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_dev.zip' 11 | }, 12 | files: [ 13 | { 14 | expand: true, 15 | cwd: '../dist_dev/', 16 | src: ['**/*.*'], 17 | dest: '/' 18 | } 19 | ] 20 | }, 21 | release: { 22 | options: { 23 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_v<%=projectconfig.general.Version%>.zip' 24 | }, 25 | files: [ 26 | { 27 | expand: true, 28 | cwd: '../dist/', 29 | src: ['**/*.*'], 30 | dest: '/' 31 | } 32 | ] 33 | }, 34 | release_latest: { 35 | options: { 36 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_latest.zip' 37 | }, 38 | files: [ 39 | { 40 | expand: true, 41 | cwd: '../dist/', 42 | src: ['**/*.*'], 43 | dest: '/' 44 | } 45 | ] 46 | }, 47 | source: { 48 | options: { 49 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe%>_src_v<%=projectconfig.general.Version%>.zip' 50 | }, 51 | files: [ 52 | { 53 | expand: true, 54 | cwd: '../', 55 | src: ['src/**/*', 'grunt/**/*', '!grunt/node_modules/**/*'], 56 | dest: '/' 57 | } 58 | ] 59 | } 60 | }; 61 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/Gruntfile.copy.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-copy' ); 6 | return { 7 | options: { 8 | processContentExclude: ['**/*.{png,gif,jpg,ico,psd}'] 9 | }, 10 | copy_to_dist_dev: { 11 | expand: true, // allow dynamic building 12 | cwd: '../src/', // change base dir 13 | //src: ['**', '!docs/**'], // source files mask 14 | src: ['**'], 15 | dest: '../dist_dev/', // destination folder 16 | flatten: false // remove all unnecessary nesting 17 | }, 18 | copy_to_dist_release: { 19 | expand: true, // allow dynamic building 20 | cwd: '../src/', // change base dir 21 | //src: ['**', '!docs/**'], // source files mask 22 | src: ['**'], 23 | dest: '../dist/', // destination folder 24 | flatten: false // remove all unnecessary nesting 25 | }, 26 | copy_to_desktop_dev: { 27 | expand: true, 28 | cwd: '../dist_dev/', 29 | src: '**', 30 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 31 | }, 32 | copy_to_desktop_release: { 33 | expand: true, 34 | cwd: '../dist/', 35 | src: '**', 36 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 37 | } 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/Gruntfile.jshint.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-jshint' ); 6 | return { 7 | dev: { 8 | options: { 9 | jshintrc: ".jshintrc-dev", 10 | ignores: [] 11 | }, 12 | defaults: ["<%=projectconfig.jsSources.dev%>"] 13 | }, 14 | release: { 15 | options: { 16 | jshintrc: ".jshintrc-release", 17 | ignores: [] 18 | }, 19 | defaults: ["<%=projectconfig.jsSources.release%>"] 20 | } 21 | 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/Gruntfile.less.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-less' ); 6 | return { 7 | 8 | // If used converts all the objects in place (mainly used for debugging purposes) 9 | allInPlace_dev: { 10 | options: { 11 | compress: false, 12 | yuicompress: false, 13 | optimization: 2, 14 | cleancss: false, 15 | paths: ['../dist_dev'] 16 | }, 17 | files: [{ 18 | expand: true, 19 | cwd: "../dist_dev", 20 | src: ["**/*.less"], 21 | ext: ".css", 22 | dest: "../dist_dev" 23 | }] 24 | }, 25 | dev: { 26 | options: { 27 | compress: '<%= projectconfig.dev.less.lessCompress%>', 28 | yuicompress: '<%= projectconfig.dev.less.lessYuiCompress%>', 29 | optimization: parseInt( 'projectconfig.dev.less.lessOptimization' ), 30 | cleancss: '<%= projectconfig.dev.less.lessCleanCss%>' 31 | }, 32 | files: { 33 | "../dist_dev/lib/css/style.css": "../src/lib/less/_root.less" 34 | } 35 | }, 36 | release: { 37 | options: { 38 | compress: '<%= projectconfig.release.less.lessCompress%>', 39 | yuicompress: '<%= projectconfig.release.less.lessYuiCompress%>', 40 | optimization: parseInt( 'projectconfig.release.less.lessOptimization' ), 41 | cleancss: '<%= projectconfig.release.less.lessCleanCss%>' 42 | }, 43 | files: { 44 | "../dist/lib/css/style.css": "../src/lib/less/_root.less" 45 | } 46 | } 47 | }; 48 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/Gruntfile.projectconfig.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | var YAML = require( 'yamljs' ); 3 | module.exports = function ( grunt ) { 4 | 'use strict'; 5 | return YAML.load( 'grunt-config.yml' ); 6 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/Gruntfile.uglify.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | /*jshint 3 | camelcase: false 4 | */ 5 | module.exports = function ( grunt ) { 6 | 'use strict'; 7 | 8 | grunt.loadNpmTasks( 'grunt-contrib-uglify' ); 9 | return { 10 | 11 | options: { 12 | mangle: '<%= projectconfig.release.uglify.mangle%>', 13 | beautify: '<%= projectconfig.release.uglify.beautify%>', 14 | preserveComments: '<%= projectconfig.release.uglify.preserveComments%>', 15 | compress: { 16 | drop_console: '<%= projectconfig.release.uglify.drop_console%>' 17 | } 18 | }, 19 | release: { 20 | files: [ 21 | { 22 | src: ['./../dist/**/*.js', '!./../dist/**/*.min.js'], 23 | dest: './../dist/', 24 | expand: true 25 | } 26 | ] 27 | } 28 | }; 29 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/gruntReplacements.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in both the dev and release 5 | # task 6 | # 7 | # In your code just use @@variable 8 | # ------------------------------------------------------------------- 9 | 10 | # You have to have at least one variable here 11 | dummy: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/gruntReplacements_dev.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the dev task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: true -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/gruntReplacements_release.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the release task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: false -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/grunt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Grunt-Deployment-10-Hello-Data-Performancetest", 3 | "version": "0.0.1", 4 | "description": "Grunt tasks (dev + release) for the Qlik Sense extension 10-Hello-Data-Performancetest", 5 | "main": "gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "Qlik Sense Extension", 11 | "qliksense-visualization-extension", 12 | "Qlik Sense", 13 | "QlikSense", 14 | "Extension" 15 | ], 16 | "author": "Stefan Walther", 17 | "license": "MIT", 18 | "dependencies": { 19 | "grunt": "~0.4.5", 20 | "grunt-contrib-clean": "~0.6.0", 21 | "grunt-cleanempty": "~1.0.3", 22 | "grunt-contrib-compress": "~0.13.0", 23 | "grunt-contrib-copy": "~0.8.0", 24 | "grunt-contrib-jshint": "^0.11.0", 25 | "grunt-contrib-less": "~1.0.0", 26 | "grunt-replace": "~0.8.0", 27 | "grunt-contrib-uglify": "~0.8.0", 28 | "q": "^1.2.0", 29 | "winreg": "0.0.12", 30 | "async": "^0.9.0", 31 | "yamljs": "^0.2.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/src/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true 75 | } 76 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/src/10-hello-data-performancetest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-01/10-Hello-Data-Performancetest/src/10-hello-data-performancetest.png -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/src/exttut-10-hello-data-performancetest.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "10-Hello-Data-Performancetest", 3 | "description" : "Comparing performance between html injection and dom object creation.", 4 | "icon" : "extension", 5 | "type" : "visualization", 6 | "version": "@@version", 7 | "preview" : "10-hello-data-performancetest.png", 8 | "author": "Stefan Walther" 9 | } -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/src/initialproperties.js: -------------------------------------------------------------------------------- 1 | /*global define*/ 2 | define( [], function () { 3 | 'use strict'; 4 | return { 5 | qHyperCubeDef: { 6 | qDimensions: [], 7 | qMeasures: [], 8 | qInitialDataFetch: [ 9 | { 10 | qWidth: 5, 11 | qHeight: 2000 12 | } 13 | ] 14 | } 15 | }; 16 | } ); 17 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/src/lib/css/style.css: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | DO NOT MODIFY THIS FILE 4 | 5 | This will be replaced with all the styles created in the src/lib/less folder 6 | 7 | */ -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/src/lib/less/_root.less: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // This is the main Less-file for all styles you want to create 3 | // 4 | // If you want to include files, use the @import command of Less 5 | // 6 | // All results will be generated to src/lib/style.css if you run 7 | // either the "dev" or "release" Grunt task 8 | // ---------------------------------------------------------------------------- 9 | 10 | .qv-object-exttut-10-hello-data-performancetest { 11 | 12 | .divContainer { 13 | position: relative; 14 | height: 100%; 15 | width: 100%; 16 | overflow: auto; 17 | } 18 | 19 | } 20 | 21 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/src/lib/less/styles.less: -------------------------------------------------------------------------------- 1 | // Main Styles (included in _root.less) 2 | 3 | .hello-world { 4 | 5 | color: @defaultColor; 6 | font-weight:bold; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/src/lib/less/variables.less: -------------------------------------------------------------------------------- 1 | // Defined variables (included in _root.less) 2 | @defaultColor: #333333; 3 | -------------------------------------------------------------------------------- /Chapters-Source/part-01/10-Hello-Data-Performancetest/src/properties.js: -------------------------------------------------------------------------------- 1 | define( [], function () { 2 | 'use strict'; 3 | 4 | // **************************************************************************************** 5 | // Dimensions & Measures 6 | // **************************************************************************************** 7 | var dimensions = { 8 | uses: "dimensions", 9 | min: 0, 10 | max: 10 11 | }; 12 | 13 | var measures = { 14 | uses: "measures", 15 | min: 0, 16 | max: 10 17 | }; 18 | 19 | var sorting = { 20 | uses: "sorting" 21 | }; 22 | 23 | // **************************************************************************************** 24 | // Property Panel Definition 25 | // **************************************************************************************** 26 | 27 | // Appearance Panel 28 | var appearancePanel = { 29 | uses: "settings" 30 | }; 31 | 32 | // Return values 33 | return { 34 | type: "items", 35 | component: "accordion", 36 | items: { 37 | dimensions: dimensions, 38 | measures: measures, 39 | sorting: sorting, 40 | appearance: appearancePanel 41 | } 42 | }; 43 | 44 | } ); 45 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # ========================= 5 | # Custom for Visual Studio 6 | # ========================= 7 | *.cs diff=csharp 8 | *.sln merge=union 9 | *.csproj merge=union 10 | *.vbproj merge=union 11 | *.fsproj merge=union 12 | *.dbproj merge=union 13 | 14 | # ========================= 15 | # Standard to msysgit 16 | # ========================= 17 | *.doc diff=astextplain 18 | *.DOC diff=astextplain 19 | *.docx diff=astextplain 20 | *.DOCX diff=astextplain 21 | *.dot diff=astextplain 22 | *.DOT diff=astextplain 23 | *.pdf diff=astextplain 24 | *.PDF diff=astextplain 25 | *.rtf diff=astextplain 26 | *.RTF diff=astextplain 27 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-qsextension": { 3 | "advancedMode": true, 4 | "extensionName": "10-AngularJS-Basics", 5 | "extensionNameSafe": "10-AngularJS-Basics", 6 | "extensionType": "extension", 7 | "extensionNamespace": "exttut-", 8 | "extensionDescription": "Basic usage of AngularJS in visualization extensions", 9 | "authorName": "Stefan Walther", 10 | "lessSupport": false, 11 | "license": "mit", 12 | "publishingYear": 2015, 13 | "creationDate": "2015-07-14", 14 | "licenceGenerated": "> \r\n> The MIT License (MIT)\r\n> \r\n> Copyright (c) 2015 Stefan Walther\r\n> \r\n> Permission is hereby granted, free of charge, to any person obtaining a copy\r\n> of this software and associated documentation files (the \"Software\"), to deal\r\n> in the Software without restriction, including without limitation the rights\r\n> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n> copies of the Software, and to permit persons to whom the Software is\r\n> furnished to do so, subject to the following conditions:\r\n> \r\n> The above copyright notice and this permission notice shall be included in all\r\n> copies or substantial portions of the Software.\r\n> \r\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n> SOFTWARE.\r\n> ", 15 | "localExtensionDir": "d:\\\\documents\\\\Qlik\\\\Sense\\\\Extensions" 16 | } 17 | } -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/CHANGELOG.yml: -------------------------------------------------------------------------------- 1 | v0.0.1: 2 | date: "2015-07-14" 3 | new: 4 | - Initial Commit 5 | enhancements: 6 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/LICENSE.md: -------------------------------------------------------------------------------- 1 | **10-AngularJS-Basics Qlik Sense Extension** is licensed under the "MIT" license: 2 | 3 | * [License](#license) 4 | * [External Libraries](#external libraries) 5 | 6 | --- 7 | 8 | ## License 9 | 10 | > 11 | > The MIT License (MIT) 12 | > 13 | > Copyright (c) 2015 Stefan Walther 14 | > 15 | > Permission is hereby granted, free of charge, to any person obtaining a copy 16 | > of this software and associated documentation files (the "Software"), to deal 17 | > in the Software without restriction, including without limitation the rights 18 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | > copies of the Software, and to permit persons to whom the Software is 20 | > furnished to do so, subject to the following conditions: 21 | > 22 | > The above copyright notice and this permission notice shall be included in all 23 | > copies or substantial portions of the Software. 24 | > 25 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | > SOFTWARE. 32 | > 33 | 34 | ## External Libraries 35 | 36 | These external libraries are used within this solution. Many thanks to the authors! 37 | 38 | **Library 1** 39 | * Name: 40 | * License: 41 | * Url: 42 | * Author: 43 | 44 | **Library 2** 45 | * Name: 46 | * License: 47 | * Url: 48 | * Author: 49 | 50 | --- 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/README.md: -------------------------------------------------------------------------------- 1 | # 01-AngularJS-Basics 2 | > Basic usage of AngularJS in visualization extensions 3 | 4 | ## Purpose and Description 5 | 6 | ## Screenshots 7 | 8 | ## Installation 9 | 10 | 1. Download the latest version 11 | 2. Qlik Sense Desktop 12 | * To install, copy all files in the .zip file to folder "C:\Users\[%Username%]\Documents\Qlik\Sense\Extensions\10-AngularJS-Basics" 13 | 3. Qlik Sense Server 14 | * See instructions [how to import an extension on Qlik Sense Server](http://help.qlik.com/sense/en-us/developer/#../Subsystems/Workbench/Content/BuildingExtensions/HowTos/deploy-extensions.htm) 15 | 16 | ## Configuration 17 | 18 | ## Contributing 19 | Contributing to this project is welcome. The process to do so is outlined below: 20 | 21 | 1. Create a fork of the project 22 | 2. Work on whatever bug or feature you wish 23 | 3. Create a pull request (PR) 24 | 25 | I cannot guarantee that I will merge all PRs but I will evaluate them all. 26 | 27 | ## Author 28 | 29 | **Stefan Walther** 30 | * http://www.yourwebsite.com 31 | * http://github.com/yourname 32 | 33 | 34 | ## Change Log 35 | 36 | See [CHANGELOG](CHANGELOG.yml) 37 | 38 | ## License & Copyright 39 | The software is made available "AS IS" without any warranty of any kind under the MIT License (MIT). 40 | 41 | See [Additional license information for this solution.](LICENSE.md) 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/.jshintrc-release: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true, 75 | "_": true 76 | } 77 | } -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/Gruntfile.clean.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-clean' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | force: true 11 | }, 12 | src: [ 13 | '../dist_dev/**/*.bak', 14 | '../dist_dev/**/*.less', 15 | '../dist_dev/**/*.tmpl' 16 | ], 17 | filter: 'isFile' 18 | }, 19 | release: { 20 | options: { 21 | force: true 22 | }, 23 | src: [ 24 | '../dist/**/*.bak', 25 | '../dist/**/*.less', 26 | '../dist/**/*.tmpl' 27 | ], 28 | filter: 'isFile' 29 | }, 30 | empty_dist_dev: { 31 | options: { 32 | force: true 33 | }, 34 | src: [ 35 | '../dist_dev/**/*' 36 | ] 37 | }, 38 | empty_dist: { 39 | options: { 40 | force: true 41 | }, 42 | src: [ 43 | '../dist/**/*' 44 | ] 45 | }, 46 | empty_desktop: { 47 | options: { 48 | force: true 49 | }, 50 | src: [ 51 | '<%=projectconfig.general.ExtensionNamespace%>/<%=projectconfig.general.ExtensionNameSafe%>/**/*' 52 | ] 53 | } 54 | }; 55 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/Gruntfile.cleanempty.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks('grunt-cleanempty'); 6 | return { 7 | 8 | options: { 9 | force: true 10 | }, 11 | all: { 12 | options: { 13 | files: false 14 | }, 15 | src: ['../dist/**/*'] 16 | } 17 | 18 | }; 19 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/Gruntfile.compress.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-compress' ); 6 | return { 7 | 8 | dev: { 9 | options: { 10 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_dev.zip' 11 | }, 12 | files: [ 13 | { 14 | expand: true, 15 | cwd: '../dist_dev/', 16 | src: ['**/*.*'], 17 | dest: '/' 18 | } 19 | ] 20 | }, 21 | release: { 22 | options: { 23 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_v<%=projectconfig.general.Version%>.zip' 24 | }, 25 | files: [ 26 | { 27 | expand: true, 28 | cwd: '../dist/', 29 | src: ['**/*.*'], 30 | dest: '/' 31 | } 32 | ] 33 | }, 34 | release_latest: { 35 | options: { 36 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe.toLowerCase()%>_latest.zip' 37 | }, 38 | files: [ 39 | { 40 | expand: true, 41 | cwd: '../dist/', 42 | src: ['**/*.*'], 43 | dest: '/' 44 | } 45 | ] 46 | }, 47 | source: { 48 | options: { 49 | archive: '../build/<%=projectconfig.general.ExtensionNamespace%><%=projectconfig.general.ExtensionNameSafe%>_src_v<%=projectconfig.general.Version%>.zip' 50 | }, 51 | files: [ 52 | { 53 | expand: true, 54 | cwd: '../', 55 | src: ['src/**/*', 'grunt/**/*', '!grunt/node_modules/**/*'], 56 | dest: '/' 57 | } 58 | ] 59 | } 60 | }; 61 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/Gruntfile.copy.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-copy' ); 6 | return { 7 | options: { 8 | processContentExclude: ['**/*.{png,gif,jpg,ico,psd}'] 9 | }, 10 | copy_to_dist_dev: { 11 | expand: true, // allow dynamic building 12 | cwd: '../src/', // change base dir 13 | //src: ['**', '!docs/**'], // source files mask 14 | src: ['**'], 15 | dest: '../dist_dev/', // destination folder 16 | flatten: false // remove all unnecessary nesting 17 | }, 18 | copy_to_dist_release: { 19 | expand: true, // allow dynamic building 20 | cwd: '../src/', // change base dir 21 | //src: ['**', '!docs/**'], // source files mask 22 | src: ['**'], 23 | dest: '../dist/', // destination folder 24 | flatten: false // remove all unnecessary nesting 25 | }, 26 | copy_to_desktop_dev: { 27 | expand: true, 28 | cwd: '../dist_dev/', 29 | src: '**', 30 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 31 | }, 32 | copy_to_desktop_release: { 33 | expand: true, 34 | cwd: '../dist/', 35 | src: '**', 36 | dest: '<%= projectconfig.general.LocalExtensionPath%>/<%= projectconfig.general.ExtensionNamespace%><%= projectconfig.general.ExtensionNameSafe%>/' 37 | } 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/Gruntfile.jshint.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | module.exports = function ( grunt ) { 3 | 'use strict'; 4 | 5 | grunt.loadNpmTasks( 'grunt-contrib-jshint' ); 6 | return { 7 | dev: { 8 | options: { 9 | jshintrc: ".jshintrc-dev", 10 | ignores: [] 11 | }, 12 | defaults: ["<%=projectconfig.jsSources.dev%>"] 13 | }, 14 | release: { 15 | options: { 16 | jshintrc: ".jshintrc-release", 17 | ignores: [] 18 | }, 19 | defaults: ["<%=projectconfig.jsSources.release%>"] 20 | } 21 | 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/Gruntfile.projectconfig.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | var YAML = require( 'yamljs' ); 3 | module.exports = function ( grunt ) { 4 | 'use strict'; 5 | return YAML.load( 'grunt-config.yml' ); 6 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/Gruntfile.uglify.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | /*jshint 3 | camelcase: false 4 | */ 5 | module.exports = function ( grunt ) { 6 | 'use strict'; 7 | 8 | grunt.loadNpmTasks( 'grunt-contrib-uglify' ); 9 | return { 10 | 11 | options: { 12 | mangle: '<%= projectconfig.release.uglify.mangle%>', 13 | beautify: '<%= projectconfig.release.uglify.beautify%>', 14 | preserveComments: '<%= projectconfig.release.uglify.preserveComments%>', 15 | compress: { 16 | drop_console: '<%= projectconfig.release.uglify.drop_console%>' 17 | } 18 | }, 19 | release: { 20 | files: [ 21 | { 22 | src: ['./../dist/**/*.js', '!./../dist/**/*.min.js'], 23 | dest: './../dist/', 24 | expand: true 25 | } 26 | ] 27 | } 28 | }; 29 | }; -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/gruntReplacements.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in both the dev and release 5 | # task 6 | # 7 | # In your code just use @@variable 8 | # ------------------------------------------------------------------- 9 | 10 | # You have to have at least one variable here 11 | dummy: false -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/gruntReplacements_dev.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the dev task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: true -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/gruntReplacements_release.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # General replacements 3 | # --- 4 | # Add variables here which should be replaced in the release task 5 | # 6 | # In your code just use e.g @@isDebug 7 | # ------------------------------------------------------------------- 8 | isDebug: false -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/grunt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Grunt-Deployment-10-AngularJS-Basics", 3 | "version": "0.0.1", 4 | "description": "Grunt tasks (dev + release) for the Qlik Sense extension 10-AngularJS-Basics", 5 | "main": "gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "Qlik Sense Extension", 11 | "qliksense-visualization-extension", 12 | "Qlik Sense", 13 | "QlikSense", 14 | "Extension" 15 | ], 16 | "author": "Stefan Walther", 17 | "license": "MIT", 18 | "dependencies": { 19 | "grunt": "~0.4.5", 20 | "grunt-contrib-clean": "~0.6.0", 21 | "grunt-cleanempty": "~1.0.3", 22 | "grunt-contrib-compress": "~0.13.0", 23 | "grunt-contrib-copy": "~0.8.0", 24 | "grunt-contrib-jshint": "^0.11.0", 25 | "grunt-contrib-less": "~1.0.0", 26 | "grunt-replace": "~0.8.0", 27 | "grunt-contrib-uglify": "~0.8.0", 28 | "q": "^1.2.0", 29 | "winreg": "0.0.12", 30 | "async": "^0.9.0", 31 | "yamljs": "^0.2.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/src/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # 4 tab indentation 12 | [*.*] 13 | indent_style = tab 14 | indent_size = 4 15 | 16 | # 2 space indentation for package.json since this is npm default 17 | [package.json] 18 | indent_style = space 19 | indent_size = 2 20 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/src/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "bitwise": true, 4 | "boss": false, 5 | "browser": true, 6 | "camelcase": false, 7 | "couch": false, 8 | "curly": true, 9 | "debug": false, 10 | "devel": false, 11 | "dojo": false, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "es5": false, 15 | "esnext": false, 16 | "evil": false, 17 | "expr": false, 18 | "forin": false, 19 | "funcscope": false, 20 | "globalstrict": false, 21 | "immed": false, 22 | "iterator": false, 23 | "jquery": false, 24 | "lastsemic": false, 25 | "latedef": true, 26 | "laxbreak": false, 27 | "laxcomma": false, 28 | "loopfunc": false, 29 | "mootools": false, 30 | "multistr": false, 31 | "newcap": false, 32 | "noarg": true, 33 | "node": false, 34 | "noempty": true, 35 | "nonew": true, 36 | "nomen": false, 37 | "nonstandard": false, 38 | "onecase": false, 39 | "onevar": false, 40 | "passfail": false, 41 | "plusplus": false, 42 | "proto": false, 43 | "prototypejs": false, 44 | "regexp": false, 45 | "regexdash": false, 46 | "rhino": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "smarttabs": false, 50 | "sub": false, 51 | "supernew": false, 52 | "strict": false, 53 | "trailing": true, 54 | "undef": true, 55 | "unused": true, 56 | "validthis": false, 57 | "white": false, 58 | "withstmt": false, 59 | "worker": false, 60 | "wsh": false, 61 | "yui": false, 62 | "globals": { 63 | "require": true, 64 | "define": true, 65 | "before": true, 66 | "beforeEach": true, 67 | "after": true, 68 | "afterEach": true, 69 | "chai": true, 70 | "sinon": true, 71 | "describe": true, 72 | "context": true, 73 | "it": true, 74 | "flush": true 75 | } 76 | } -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/src/02-angularjs-basics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/Chapters-Source/part-02/02-AngularJS-Basics/src/02-angularjs-basics.png -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/src/exttut-02-angularjs-basics.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | './properties', 3 | './initialproperties', 4 | 'text!./template.ng.html' 5 | ], 6 | function ( props, initProps, ngTemplate ) { 7 | 'use strict'; 8 | 9 | return { 10 | definition: props, 11 | initialProperties: initProps, 12 | snapshot: {canTakeSnapshot: true}, 13 | template: ngTemplate, 14 | controller: ['$scope', function ( $scope ) { 15 | $scope.myTitle = 'This is my AngularJS table'; 16 | console.log('layout', $scope.layout); 17 | }] 18 | }; 19 | } ); 20 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/src/exttut-02-angularjs-basics.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "02-AngularJS-Basics", 3 | "description" : "Basic usage of AngularJS in visualization extensions", 4 | "icon" : "extension", 5 | "type" : "visualization", 6 | "version": "@@version", 7 | "preview" : "02-angularjs-basics.png", 8 | "author": "Stefan Walther" 9 | } -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/src/initialproperties.js: -------------------------------------------------------------------------------- 1 | define( [], function () { 2 | 'use strict'; 3 | return { 4 | qHyperCubeDef: { 5 | qDimensions: [], 6 | qMeasures: [], 7 | qInitialDataFetch: [ 8 | { 9 | qWidth: 10, 10 | qHeight: 50 11 | } 12 | ] 13 | } 14 | }; 15 | } ); 16 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/src/properties.js: -------------------------------------------------------------------------------- 1 | define( [], function () { 2 | 'use strict'; 3 | 4 | var dimensions = {uses: "dimensions"}; 5 | var measures = { uses: "measures" }; 6 | var sorting = { uses: "sorting" }; 7 | var addons = { uses: "addons" }; 8 | var appearancePanel = { uses: "settings" }; 9 | return { 10 | type: "items", 11 | component: "accordion", 12 | items: { 13 | dimensions: dimensions, 14 | measures: measures, 15 | sorting: sorting, 16 | appearance: appearancePanel 17 | } 18 | }; 19 | } ); 20 | -------------------------------------------------------------------------------- /Chapters-Source/part-02/02-AngularJS-Basics/src/template.ng.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 16 | 17 | 18 |
8 | 9 |
14 | {{col.qText}} 15 |
19 |
-------------------------------------------------------------------------------- /Todos.md: -------------------------------------------------------------------------------- 1 | - auto-linking to the online-help would be extremely cool 2 | - Gulp 3 | - Generate qliksite.yml file 4 | - ideally change lastUpdate programmatically 5 | - rss to tutorial files? 6 | - Assemble 7 | - find a good solution for co-authors 8 | 9 | ## Content 10 | - Redo some of the screenshots (especially in the custom properties section) 11 | - AngularJS filters: http://fdietz.github.io/recipes-with-angular-js//filters/formatting-string-with-currency-filter.html 12 | 13 | ## Good tutorials 14 | 15 | - https://www.angular-meteor.com/tutorials/socially/angular2/user-accounts-authentication-and-permissions 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qliksense-extension-tutorial", 3 | "version": "0.14.2", 4 | "description": "Comprehensive tutorial to start developing Qlik Sense Extensions.", 5 | "keywords": [ 6 | "chart", 7 | "examples", 8 | "examples", 9 | "extension", 10 | "hypercube", 11 | "property panel", 12 | "qlik", 13 | "qlik sense", 14 | "qlik-sense", 15 | "qliksense", 16 | "qliksense-visualization-extension", 17 | "tutorial", 18 | "visualization", 19 | "visualization-extension", 20 | "walkthrough" 21 | ], 22 | "homepage": "https://github.com/stefanwalther/qliksense-extension-tutorial", 23 | "bugs": { 24 | "url": "https://github.com/stefanwalther/qliksense-extension-tutorial/issues" 25 | }, 26 | "license": "CC-BY-4.0", 27 | "author": "Stefan Walther", 28 | "main": "-", 29 | "directories": { 30 | "doc": "docs" 31 | }, 32 | "repository": { 33 | "type": "git", 34 | "url": "https://github.com/stefanwalther/qliksense-extension-tutorial.git" 35 | }, 36 | "scripts": { 37 | "test": "echo \"Error: no test specified\" && exit 1" 38 | }, 39 | "dependencies": {}, 40 | "devDependencies": {} 41 | } 42 | -------------------------------------------------------------------------------- /src/images/banner/06-Visualization-Extension-Tutorial--Introduction-Using-Properties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/images/banner/06-Visualization-Extension-Tutorial--Introduction-Using-Properties.png -------------------------------------------------------------------------------- /src/part-00/00-toc/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Visualization Extensions in Qlik Sense" 3 | layout: area-overview 4 | pageOpts: 5 | isDisqus: false 6 | isToc: true 7 | ghOpts: 8 | isEditButton: false 9 | isStarButton: false 10 | --- 11 | 12 | -------------------------------------------------------------------------------- /src/part-00/01-about/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: About this tutorial 3 | sub-title: Another kind of a tutorial ... A living tutorial ... 4 | lastUpdate: "2015-05-29" 5 | order: 0 6 | abstract: 7 | draft: false 8 | tags: 9 | - Qlik Sense 10 | - visualization extension 11 | - extension 12 | --- 13 | 14 | In the past I was writing quite a lot of article on [my private blog](http://qliksite.io) which is fine in general, but I realized when writing a tutorial, a blog is not really the ideal format. 15 | 16 | So it's time to try something new: ***A living tutorial***. 17 | 18 | ## What's a "Living Tutorial"? 19 | 20 | The main idea behind publishing this tutorial to [GitHub](http://github.com) is, that a really good tutorial should probably never be finished. If there are changes to be made (either in the code or the descriptive text), it should just be easy to make these changes and publish them. Certainly not only for me - [the primary author](https://github.com/stefanwalther) - but also for other people. 21 | 22 | **So I invite you to not only consume, but also to participate!** 23 | 24 | ## Folder structure for code samples 25 | 26 | If there is some code related to a chapter, the code folder is always structured the same way: 27 | 28 | Folder | Description 29 | --------------- | ------------------------------------------------------------- 30 | `build` | Folder containing a zip-file called *_latest.zip with the latest version 31 | `dist` | Introduced in later chapters 32 | `grunt` | Grunt tasks for my internal deployment system, you can ignore it as of now. I'll talk about it in some of the later chapters. 33 | `src` | The **source code** used for the given chapter 34 | 35 | {{#hidden}} 36 | ## Contributing 37 | {{/hidden}} 38 | 39 | -------------------------------------------------------------------------------- /src/part-01/00-TOC/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Table of Contents" 3 | slug: 00-TOC 4 | lastUpdate: "2015-06-16" 5 | order: 1 6 | type: 7 | abstract: 8 | draft: false 9 | tags: 10 | - visualization extension 11 | - extension 12 | - Qlik Sense 13 | - tutorial 14 | --- 15 | 16 | {{doc 'toc'}} 17 | 18 | -------------------------------------------------------------------------------- /src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_description.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_description.png -------------------------------------------------------------------------------- /src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_icon.png -------------------------------------------------------------------------------- /src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_name.png -------------------------------------------------------------------------------- /src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_output.png -------------------------------------------------------------------------------- /src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_output_multiplied.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_output_multiplied.png -------------------------------------------------------------------------------- /src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/03-Lets-Get-Started--Hello-World-Example/images/03_preview.png -------------------------------------------------------------------------------- /src/part-01/04-Debugging-and-Web-Developer-Tools/images/04_ChromeWebDevTools_Inspect_Change_Elements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/04-Debugging-and-Web-Developer-Tools/images/04_ChromeWebDevTools_Inspect_Change_Elements.png -------------------------------------------------------------------------------- /src/part-01/04-Debugging-and-Web-Developer-Tools/images/04_Chromes_Web_DevTools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/04-Debugging-and-Web-Developer-Tools/images/04_Chromes_Web_DevTools.png -------------------------------------------------------------------------------- /src/part-01/04-Debugging-and-Web-Developer-Tools/images/04_Console_Sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/04-Debugging-and-Web-Developer-Tools/images/04_Console_Sample.png -------------------------------------------------------------------------------- /src/part-01/04-Debugging-and-Web-Developer-Tools/images/04_DevTools_in_QlikSenseDesktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/04-Debugging-and-Web-Developer-Tools/images/04_DevTools_in_QlikSenseDesktop.png -------------------------------------------------------------------------------- /src/part-01/05-Improving-the-Hello-World-Experience/images/05_DesiredResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/05-Improving-the-Hello-World-Experience/images/05_DesiredResult.png -------------------------------------------------------------------------------- /src/part-01/05-Improving-the-Hello-World-Experience/images/05_HelloWorld_ConsoleLog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/05-Improving-the-Hello-World-Experience/images/05_HelloWorld_ConsoleLog.png -------------------------------------------------------------------------------- /src/part-01/05-Improving-the-Hello-World-Experience/images/05_InitialPropertyPanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/05-Improving-the-Hello-World-Experience/images/05_InitialPropertyPanel.png -------------------------------------------------------------------------------- /src/part-01/05-Improving-the-Hello-World-Experience/images/05_PreviewImg_After.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/05-Improving-the-Hello-World-Experience/images/05_PreviewImg_After.png -------------------------------------------------------------------------------- /src/part-01/05-Improving-the-Hello-World-Experience/images/05_PreviewImg_Before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/05-Improving-the-Hello-World-Experience/images/05_PreviewImg_Before.png -------------------------------------------------------------------------------- /src/part-01/06-Introduction-to-Using-Properties/images/06_Accordion_Concept.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/06-Introduction-to-Using-Properties/images/06_Accordion_Concept.png -------------------------------------------------------------------------------- /src/part-01/06-Introduction-to-Using-Properties/images/06_Console_Properties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/06-Introduction-to-Using-Properties/images/06_Console_Properties.png -------------------------------------------------------------------------------- /src/part-01/06-Introduction-to-Using-Properties/images/06_DefaultProperties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/06-Introduction-to-Using-Properties/images/06_DefaultProperties.png -------------------------------------------------------------------------------- /src/part-01/06-Introduction-to-Using-Properties/images/06_More_BuiltIn_Properties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/06-Introduction-to-Using-Properties/images/06_More_BuiltIn_Properties.png -------------------------------------------------------------------------------- /src/part-01/07-Custom-Properties/images/07-Custom-header-with-textboxes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/07-Custom-Properties/images/07-Custom-header-with-textboxes.png -------------------------------------------------------------------------------- /src/part-01/07-Custom-Properties/images/07-Custom-section-with-headers-and-items.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/07-Custom-Properties/images/07-Custom-section-with-headers-and-items.png -------------------------------------------------------------------------------- /src/part-01/07-Custom-Properties/images/07-Default-appearance-section.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/07-Custom-Properties/images/07-Default-appearance-section.png -------------------------------------------------------------------------------- /src/part-01/07-Custom-Properties/images/07-Textbox-property-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/07-Custom-Properties/images/07-Textbox-property-default.png -------------------------------------------------------------------------------- /src/part-01/07-Custom-Properties/images/07-Two-Textboxes-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/07-Custom-Properties/images/07-Two-Textboxes-default.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08-open-data-load-editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08-open-data-load-editor.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08-sample-script.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08-sample-script.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08_Custom_qInitialDataFetch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08_Custom_qInitialDataFetch.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08_Default_Object_Display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08_Default_Object_Display.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08_Default_Property_Panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08_Default_Property_Panel.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08_Default_qInitialDataFetch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08_Default_qInitialDataFetch.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08_TableRendering_Result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08_TableRendering_Result.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08_Table_ConsoleLog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08_Table_ConsoleLog.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08_Table_Data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08_Table_Data.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08_Thead_All.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08_Thead_All.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08_Thead_Dims.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08_Thead_Dims.png -------------------------------------------------------------------------------- /src/part-01/08-Hello-Data/images/08_qMatrix_Explanation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-01/08-Hello-Data/images/08_qMatrix_Explanation.png -------------------------------------------------------------------------------- /src/part-01/10-Hello-Data-Improved/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hello Data - Improved 3 | lastUpdate: "2015-05-29" 4 | abstract: Working with data in a Qlik Sense visualization extension. 5 | tags: 6 | draft: true 7 | --- 8 | 9 | ## Styling your table 10 | Adding a nice style for your table is now really a piece of cake: 11 | 12 | 1. Create a CSS file with some nice table styles 13 | 2. Load the style sheet as described in the previous chapter 14 | 15 | ```css 16 | TBD 17 | 18 | ``` 19 | 20 | {{#hint}} 21 | TBD 22 | 23 | {{/hint}} 24 | 25 | ## Enabling vertical scrolling 26 | 27 | Enabling basic vertical scrolling (without having fixed table headers) can be implemented e.g. by 28 | 29 | * surrounding the table with a `div` 30 | * and enable scrolling by using CSS' `overflow` 31 | 32 | The final structure should look like this: 33 | 34 | ```css 35 | .qv-object-hello-data-improved .container { 36 | position:relative; 37 | height: 100%; 38 | overflow: auto; 39 | } 40 | ``` 41 | 42 | ```html 43 |
44 | 45 | ... 46 |
47 |
48 | ``` 49 | 50 | ## Support the selection model 51 | 52 | ## Data paging 53 | 54 | ## HTML injection vs. DOM-object creation 55 | If you have a look at some of the published example in the online help, you'll find different variants how to manipulate the browser's content (DOM - document object model) when e.g. creating a table as in our Hello-Data example. 56 | 57 | ### Html injection 58 | 59 | ### DOM object creation 60 | 61 | ### Table API 62 | With Qlik Sense 2.1 a new 63 | 64 | ### Surprise 65 | While writing this chapter I did some research on the performance of several approaches how to modify existing web pages. 66 | -------------------------------------------------------------------------------- /src/part-01/12-Visualization-Extension-using-HighCharts/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Table of Contents" 3 | lastUpdate: "" 4 | draft: true 5 | tags: 6 | charts 7 | highcharts 8 | library 9 | --- 10 | -------------------------------------------------------------------------------- /src/part-02/02-The-Angular-Way--Basics/images/02-AngularJS-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-02/02-The-Angular-Way--Basics/images/02-AngularJS-table.png -------------------------------------------------------------------------------- /src/part-02/02-The-Angular-Way--Basics/images/02-angular-version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-02/02-The-Angular-Way--Basics/images/02-angular-version.png -------------------------------------------------------------------------------- /src/part-02/02-The-Angular-Way--Basics/images/02-layout-console-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-02/02-The-Angular-Way--Basics/images/02-layout-console-output.png -------------------------------------------------------------------------------- /src/part-02/02-The-Angular-Way--Basics/images/02-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-02/02-The-Angular-Way--Basics/images/02-output.png -------------------------------------------------------------------------------- /src/part-02/03-The-Angular-Way--Directives/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The Angular Way: Directives" 3 | lastUpdate: "" 4 | type: chapter 5 | draft: true 6 | --- 7 | 8 | -------------------------------------------------------------------------------- /src/part-02/04-The-Angular-Way--Services/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The Angular Way: Services" 3 | lastUpdate: "" 4 | type: chapter 5 | order: -1 6 | draft: true 7 | --- -------------------------------------------------------------------------------- /src/part-02/05-The-Angular-Way--Filter/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The Angular Way: Filter" 3 | lastUpdate: "" 4 | type: chapter 5 | order: -1 6 | draft: true 7 | --- -------------------------------------------------------------------------------- /src/part-02/100-The-Angular-Way-Summary-and-Why/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The AngularJS Way: Summary and Why Using AngularJS" 3 | draft: false 4 | --- 5 | 6 | ## Why using AngularJS? 7 | You might ask yourself now why you should learn how to use a new framework "just" to implement AngularJS based visualization extensions for Qlik Sense. 8 | It is certainly up to you, I wouldn't say that the one or the other approach is better. 9 | 10 | Here are some reasons why I have fully adopted this approach: 11 | 12 | * It makes data-binding much easier 13 | * Especially when writing more complex and larger Qlik Sense visualization extensions it helps you to keep your code organized and it reduces the dependencies, so maintaining a larger code-base is much, much easier. 14 | * As soon as you start working with AngularJS you'll understand much better what's going on in the Qlik Sense client. 15 | * It's just fun learning the most popular framework to build web apps out there 16 | 17 | ## Learn by examples 18 | Much better than any tutorial is to review existing solutions and their code, here's a collection of visualization extensions using the AngularJS approach: 19 | 20 | * [AngularChart: Official AngularJS example of the Qlik Sense developer help](http://help.qlik.com/sense/2.0/en-us/developer/Subsystems/Extensions/Content/Examples/angular-chart-extension-example.htm) 21 | * [sense-on-off-switch](https://github.com/stefanwalther/sense-on-off-switch) 22 | * [sense-media-box](https://github.com/stefanwalther/sense-media-box) 23 | * [sense-themable-kpi-tile](https://github.com/stefanwalther/sense-themable-kpi-tile) 24 | * [sense-range-slider](https://github.com/stefanwalther/sense-range-slider) 25 | * [sense-funnel](https://github.com/stefanwalther/sense-funnel) 26 | * [sense-qr-code](https://github.com/stefanwalther/sense-qr-code) 27 | -------------------------------------------------------------------------------- /src/part-02/90-AngularJS-Recipes/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "AngularJS Recipes" 3 | draft: true 4 | --- 5 | 6 | - [How to get a reference to an AngularJS service](#how-to-get-a-reference-to-an-angularjs-service) 7 | 8 | --- 9 | 10 | ## How to get a reference to an AngularJS service 11 | 12 | If you want to work with one of the existing AngularJS services, you need a get a reference. 13 | 14 | ```js 15 | define( [ 16 | 'angular' 17 | ], function ( angular ) { 18 | 19 | // Get a reference to the $timeout service 20 | var $injector = angular.injector( ['ng'] ); 21 | var $timeout = $injector.get( "$timeout" ); 22 | 23 | // Your code, where you can now use $timeout 24 | 25 | }); 26 | ``` 27 | -------------------------------------------------------------------------------- /src/part-03/01-exporting-data/images/export-failed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-03/01-exporting-data/images/export-failed.png -------------------------------------------------------------------------------- /src/part-03/01-exporting-data/images/exportdata-context-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-03/01-exporting-data/images/exportdata-context-menu.png -------------------------------------------------------------------------------- /src/part-03/01-exporting-data/images/qmc-export-exportdata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-03/01-exporting-data/images/qmc-export-exportdata.png -------------------------------------------------------------------------------- /src/part-03/01-exporting-data/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Enable/Disable support to export data" 3 | sub-title: "Learn how to modify your visualization extension to enable or disable the ability to export the data on right click." 4 | --- 5 | 6 | Qlik Sense 3.0 introduces the possibility to enable/disable the functionality to export the underlying data of a visualization extension. 7 | 8 | To define whether exporting data should be enabled or not, use the property `exportData` in the section `support`: 9 | 10 | 11 | ```js 12 | 13 | definition: { 14 | ... 15 | }, 16 | support: { 17 | exportData: true 18 | }, 19 | initialProperties: { 20 | ... 21 | }, 22 | ... 23 | 24 | 25 | ``` 26 | 27 | The following context menu will then be shown: 28 | 29 | ![](images/exportdata-context-menu.png) 30 | 31 | 32 | ## Conditional enablement of `exportData` 33 | 34 | If the user wants to export the data, but the extension does not (yet) contain any data, the following notification will be shown: 35 | 36 | ![](images/export-failed.png) 37 | 38 | To prevent such a message, `exportData` can also return a function instead of a boolean value: 39 | 40 | ```js 41 | 42 | support: { 43 | exportData: function( layout ) { 44 | // The context menu will only be enabled if there is data to export. 45 | return layout.qHyperCube.qDataPages[0].qMatrix.length; 46 | } 47 | } 48 | 49 | ``` 50 | 51 | ## Qlik Sense server & export (`exportData`) 52 | 53 | Note that settings defined in your Qlik sense visualization extension can be overruled in Qlik Sense server's management console: 54 | 55 | ![](images/qmc-export-exportdata.png) 56 | -------------------------------------------------------------------------------- /src/part-03/02-printing-extensions/images/qmc-export-exportdata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-03/02-printing-extensions/images/qmc-export-exportdata.png -------------------------------------------------------------------------------- /src/part-03/02-printing-extensions/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Enabling support to print visualization extensions" 3 | --- 4 | 5 | In Qlik Sense 3.0 support for printing extensions has been added. Therefore it is now possible to: 6 | 7 | - Export a single extension as image (right click) 8 | - Include visualization extensions in stories and print the story. 9 | - Include visualization extensions if a PDF for the current sheet is created. 10 | 11 | To enable this functionality the following changes need to be made to (existing) visualization extensions: 12 | 13 | ## Meta data 14 | 15 | To tell Qlik Sense that your visualization extension should be enabled for printing, add the following properties: 16 | 17 | ```js 18 | 19 | definition: { 20 | ... 21 | }, 22 | support: { 23 | export: true 24 | }, 25 | paint: function() { 26 | ... 27 | }, 28 | ... 29 | 30 | ``` 31 | 32 | ## Finished rendering notification 33 | 34 | Then in the `paint` method the printing service needs to be informed that the extension has finished rendering: 35 | 36 | ```js 37 | 38 | // ... 39 | paint: function() { 40 | 41 | return qlik.Promise.resolve(); 42 | } 43 | // ... 44 | 45 | ``` 46 | 47 | So even in case your visualization extension is loading data from an external source and it takes some time that rendering is finished, this solution will take care of that: 48 | 49 | ```js 50 | paint: function() { 51 | 52 | whateverAsyncTask().then( function() { 53 | return qlik.Promise.resolve(); 54 | }); 55 | 56 | } 57 | ``` 58 | 59 | ## Qlik Sense server & printing (`export`) 60 | 61 | Note that settings defined in your Qlik sense visualization extension can be overruled in Qlik Sense server's management console: 62 | 63 | ![](images/qmc-export-exportdata.png) 64 | 65 | -------------------------------------------------------------------------------- /src/part-04/01-Deployment-Checklist/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Deployment Checklist 3 | sub-title: Things to consider before you go live with your visualization extension. 4 | lastUpdate: "2016-06-23" 5 | draft: false 6 | --- 7 | 8 | ## Some basic rules to follow 9 | * Remove all `console.%()` statements. 10 | * Remove all `debugger;` statements (!!!{). 11 | 12 | {{#hint}} 13 | Use any automated deployment system like [grunt](http://gruntjs.com/) or [gulp](http://gulpjs.com/) to automate this task! 14 | {{/hint}} 15 | 16 | ## Test Qlik Sense Server 17 | Ensure that you test your solution also on Qlik Sense Server, not only in the desktop environment. 18 | 19 | ## Automate it! 20 | 21 | One the one hand it's fine to have a deployment checklist, but on the other hand stupid, repetitive work should be minimized. 22 | So I personally prefer to automate as many tasks in my daily work as possible. 23 | 24 | Have a look at the following projects to get an idea of how repetitive tasks related to extension development can be automated: 25 | 26 | * [sense-go](https://github.com/stefanwalther/sense-go) 27 | * [generator-qsextension](https://github.com/stefanwalther/generator-qsExtension) 28 | -------------------------------------------------------------------------------- /src/part-05/Advanced-More-On-Custom-Properties/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3 | lastUpdate: "2015-05-29" 4 | draft: true 5 | --- 6 | * More components 7 | * Show conditions 8 | * Tips to structure your property definitions 9 | * Tips to organize your references 10 | * Use external sources 11 | -------------------------------------------------------------------------------- /src/part-07/5000-Using-Bootstrap-CSS-in-Visualization-Extensions/images/5000/5000_Boostrap_Clash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-07/5000-Using-Bootstrap-CSS-in-Visualization-Extensions/images/5000/5000_Boostrap_Clash.png -------------------------------------------------------------------------------- /src/part-07/5000-Using-Bootstrap-CSS-in-Visualization-Extensions/images/5000/5000_Bootstrap_styled_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-07/5000-Using-Bootstrap-CSS-in-Visualization-Extensions/images/5000/5000_Bootstrap_styled_button.png -------------------------------------------------------------------------------- /src/part-07/5000-Using-Bootstrap-CSS-in-Visualization-Extensions/images/5000/5000_FolderStructure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-07/5000-Using-Bootstrap-CSS-in-Visualization-Extensions/images/5000/5000_FolderStructure.png -------------------------------------------------------------------------------- /src/part-09/1000-Appendix/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Appendix 3 | lastUpdate: "2015-05-29" 4 | order: 10000 5 | abstract: 6 | tags: 7 | --- 8 | 9 | 10 | * [Resources](1001-Appendix-Resources.md) 11 | * [Troubleshooting & FAQ](1002-Troubleshooting-FAQ.md) 12 | * [Allowed Mime Types in Qlik Sense 2.1.1](1004-Allowed-Mime-Types-2.1.1.md) 13 | * What's New 14 | * [What's New in Qlik Sense 1.1] (2011-Appendix-Whats-New-in-Qlik-Sense-1.1.md) 15 | -------------------------------------------------------------------------------- /src/part-09/1001-Appendix-Resources/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Resources & Articles 3 | lastUpdate: "2015-05-29" 4 | order: 10010 5 | abstract: 6 | tags: 7 | --- 8 | 9 | 10 | ## Tutorials 11 | * **How to Build a Qlik Sense Extension with D3** 12 | * Very good and comprehensive article by Speros how to create a Visualization Extension in Qlik Sense leveraging the [D3](http://d3js.org) library. 13 | http://blog.axc.net/tutorial-how-to-build-a-qlik-sense-extension-with-d3/ 14 | -------------------------------------------------------------------------------- /src/part-09/1002-Troubleshooting-FAQ/images/changes-not-reflected_DevToolsSettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-09/1002-Troubleshooting-FAQ/images/changes-not-reflected_DevToolsSettings.png -------------------------------------------------------------------------------- /src/part-09/1050-Appendix-First-Steps-with-Qlik-Sense/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: First Steps with Qlik Sense 3 | lastUpdate: "2015-05-29" 4 | draft: true 5 | --- -------------------------------------------------------------------------------- /src/part-09/2013-Appendix-Whats-New-in-Qlik-Sense-2.1.1/images/2013_usage-matrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/qliksense-extension-tutorial/b51b90d27e1cfced8ebe7e11efacc2497714b796/src/part-09/2013-Appendix-Whats-New-in-Qlik-Sense-2.1.1/images/2013_usage-matrix.png -------------------------------------------------------------------------------- /src/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Visualization Extensions: Table of Contents" 3 | sub-title: "Get started with the visualization extension concept for Qlik Sense" 4 | layout: area-overview 5 | pageOpts: 6 | isDisqus: false 7 | isToc: true 8 | ghOpts: 9 | isEditButton: false 10 | isStarButton: false 11 | --- 12 | --------------------------------------------------------------------------------