summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Vobornik <pvoborni@redhat.com>2014-05-16 17:54:11 +0200
committerPetr Vobornik <pvoborni@redhat.com>2014-06-11 14:36:00 +0200
commitc8a2d28237cf6d1a386687c7e57c2b7e9b3f600a (patch)
treecf55cc3d82e6fdf781d44e3b4c310a290b609d03
parentcbf16ef15121212255b4683fdfc5715276728b76 (diff)
downloadfreeipa-plugin-apibrowser.tar.gz
freeipa-plugin-apibrowser.tar.xz
freeipa-plugin-apibrowser.zip
API browser pluginplugin-apibrowser
This is a crude example of a plugin which: - adds custom dropdown menu to utility area of navigation - have it's own structure of hash part of URL - custom route+handler - have a custom facet with custom widget NOTE: this is ONLY an EXAMPLE. Never add plugins which should be part of core server to this directory.
-rw-r--r--install/ui/src/plugins/apibrowser/apibrowser.js243
-rw-r--r--install/ui/src/plugins/apibrowser/jsl.conf128
2 files changed, 371 insertions, 0 deletions
diff --git a/install/ui/src/plugins/apibrowser/apibrowser.js b/install/ui/src/plugins/apibrowser/apibrowser.js
new file mode 100644
index 000000000..94e98a81e
--- /dev/null
+++ b/install/ui/src/plugins/apibrowser/apibrowser.js
@@ -0,0 +1,243 @@
+
+define([
+ 'dojo/_base/lang',
+ 'dojo/_base/declare',
+ 'dojo/dom-construct',
+ 'dojo/on',
+ 'freeipa/jquery',
+ 'freeipa/json2',
+ 'freeipa/extend',
+ 'freeipa/navigation',
+ 'freeipa/phases',
+ 'freeipa/reg',
+ 'freeipa/facets/Facet',
+ 'freeipa/widgets/DropdownWidget'
+],function(lang, declare, construct, on, $, JSON, extend, navigation, phases, reg, Facet, DropdownWidget) {
+
+/**
+ * Widget which display facet's public state.
+ *
+ * Public state usually corresponds to hash part of URL (facet doesn't care,
+ * it's handle by different subsystem.
+ *
+ * The simplest widget just has to implement `create` or `render` method and
+ * set couple properties (handled by mixing-in spec)
+ *
+ * @class
+ */
+var StateWidget = declare([], {
+
+ init: function() {
+ // not really nice code. It should be injected into the widget.
+ var facet = this.facet || this.parent;
+ if (facet) {
+ on(facet, 'facet-state-change', lang.hitch(this, this.on_state_change));
+ }
+ },
+
+ on_state_change: function(event) {
+ if (!this.dom_node) return;
+ this.render_hash();
+ },
+
+ render: function() {
+ this.dom_node = construct.create('div', {
+ 'class': this['class']
+ });
+
+ if (this.container_node) {
+ construct.place(this.dom_node, this.container_node);
+ }
+ this.render_hash();
+ return this.dom_node;
+ },
+
+ render_hash: function() {
+ construct.empty(this.dom_node);
+ this.dom_node.innerHTML = JSON.stringify(this.parent.state.clone());
+ },
+
+ constructor: function(spec) {
+ spec = spec || {};
+ declare.safeMixin(this, spec);
+ }
+
+});
+
+/**
+ * BrowserFacet
+ *
+ * We require custom facet because of non-standard URL hash part.
+ *
+ * @class
+ */
+var BrowserFacet = declare([Facet], {
+
+ /**
+ * Custom serialization of facet state into URL hash.
+ *
+ * This method might be removed and moved to different component since
+ * it should not be Facet's responsibility.
+ *
+ * @return {string} hash
+ */
+ create_hash: function(router) {
+
+ var state = this.state.clone();
+ var path = [router.route_prefix, 'api'];
+ if (state.uri) {
+ path.push(state.uri);
+ }
+ if (state.urlparam) {
+ path.push(state.urlparam);
+ }
+
+ var hash = path.join('/');
+ window.console.log(hash);
+ return hash;
+ }
+});
+
+
+
+/**
+ * API Browser plugin
+ *
+ * Browse API
+ *
+ * @class apibrowser
+ * @singleton
+ */
+var apibrowser = {
+
+ menu_dropdown: null,
+
+ facet_spec: {
+ name: 'apibrowser',
+
+ // use:
+ // - `main` to show navigation on the top
+ // - `simple` to fill entire page
+ preferred_container: 'main',
+
+ 'class': 'container-fluid', // for styling
+ widgets: [
+ // some widgets
+ {
+ $type: 'html',
+ name: 'html',
+ html: '<h1>API Browser</h1>'
+ },
+ {
+ $type: 'api_state',
+ name: 'state'
+ }
+ ]
+ },
+
+ /**
+ * Create and add dropdown menu to utility area of navigation
+ */
+ create_menu_dropdown: function() {
+
+ this.menu_dropdown = new DropdownWidget({
+ el_type: 'li',
+ name: 'api-browser-menu',
+ right_aligned: true,
+ // can be uncommented if you don't want to implement `create_menu_toggle`
+ // toggle_text: 'API Browser ',
+ // toggle_class: '',
+ // toggle_icon: 'fa fa-angle-down',
+ items: [
+ {
+ name: 'browser',
+ label: 'Browser',
+ icon: 'fa-user',
+ data: '/api/foo'
+ },
+ {
+ 'class': 'divider'
+ },
+ {
+ name: 'about',
+ label: 'Browser 2',
+ icon: 'fa-question',
+ data: '/api/foo/bar/abc=baz'
+ }
+ ]
+ });
+ on(this.menu_dropdown, 'item-click', lang.hitch(this, this.on_dropdown_click));
+
+ this.menu_dropdown.set('toggle_content', this.create_menu_toggle());
+ var el = this.menu_dropdown.render();
+
+ extend.add_menu_utility(el);
+ },
+
+ /**
+ * This is optional but it's a way to add icon before text
+ */
+ create_menu_toggle: function() {
+ var nodes = [];
+ nodes.push(construct.create('span', { 'class': 'fa fa-star' }));
+ nodes.push(construct.create('span', { innerHTML: ' API browser' }));
+ nodes.push(construct.create('b', { 'class': 'caret' }));
+ return nodes;
+ },
+
+ on_dropdown_click: function (item) {
+
+ // you can make decision on item properties
+ //
+ // by default just pass hash to router
+
+ var facet = reg.facet.get('apibrowser');
+ navigation.show_generic(item.data, facet);
+ // there is a bug that it doesn't collapse the menu on small screens
+ },
+
+ /**
+ * Handler of our custom route
+ */
+ route_handler: function(event, router) {
+ if (router.check_clear_ignore()) return;
+
+ // always get apibrowser facet
+ var facet = reg.facet.get('apibrowser');
+ facet.reset_state(event.params);
+ router.show_facet(facet);
+ },
+
+ register: function () {
+ var fa = reg.facet;
+ var w = reg.widget;
+
+ fa.register({
+ type: 'apibrowser',
+ factory: BrowserFacet,
+ spec: this.facet_spec
+ });
+
+ w.register('api_state', StateWidget);
+ w.register_post_op('api_state', function(obj, spec, context) {
+ obj.init();
+ return obj;
+ });
+ },
+
+ initialize: function () {
+ this.create_menu_dropdown();
+ var self = this;
+
+ // add route to router
+ extend.add_route('/api/*urlparam', function(event) {
+ self.route_handler(event, this);
+ });
+ }
+};
+
+phases.on('registration', lang.hitch(apibrowser, apibrowser.register));
+phases.on('init', lang.hitch(apibrowser, apibrowser.initialize), 20);
+
+ return apibrowser;
+}); \ No newline at end of file
diff --git a/install/ui/src/plugins/apibrowser/jsl.conf b/install/ui/src/plugins/apibrowser/jsl.conf
new file mode 100644
index 000000000..ef43a7cdb
--- /dev/null
+++ b/install/ui/src/plugins/apibrowser/jsl.conf
@@ -0,0 +1,128 @@
+#
+# Configuration File for JavaScript Lint 0.3.0
+# Developed by Matthias Miller (http://www.JavaScriptLint.com)
+#
+# This configuration file can be used to lint a collection of scripts, or to enable
+# or disable warnings for scripts that are linted via the command line.
+#
+
+### Warnings
+# Enable or disable warnings based on requirements.
+# Use "+WarningName" to display or "-WarningName" to suppress.
+#
++no_return_value # function {0} does not always return a value
++duplicate_formal # duplicate formal argument {0}
++equal_as_assign # test for equality (==) mistyped as assignment (=)?{0}
++var_hides_arg # variable {0} hides argument
++redeclared_var # redeclaration of {0} {1}
++anon_no_return_value # anonymous function does not always return a value
++missing_semicolon # missing semicolon
++meaningless_block # meaningless block; curly braces have no impact
++comma_separated_stmts # multiple statements separated by commas (use semicolons?)
++unreachable_code # unreachable code
++missing_break # missing break statement
++missing_break_for_last_case # missing break statement for last case in switch
++comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
++inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
++useless_void # use of the void type may be unnecessary (void is always undefined)
++multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
++use_of_label # use of label
+-block_without_braces # block statement without curly braces
++leading_decimal_point # leading decimal point may indicate a number or an object member
++trailing_decimal_point # trailing decimal point may indicate a number or an object member
++octal_number # leading zeros make an octal number
++nested_comment # nested comment
++misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
++ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
++empty_statement # empty statement or extra semicolon
+-missing_option_explicit # the "option explicit" control comment is missing
++partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
++dup_option_explicit # duplicate "option explicit" control comment
++useless_assign # useless assignment
++ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
++ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent)
++missing_default_case # missing default case in switch statement
++duplicate_case_in_switch # duplicate case in switch statements
++default_not_at_end # the default case is not at the end of the switch statement
++legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
++jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
++useless_comparison # useless comparison; comparing identical expressions
++with_statement # with statement hides undeclared variables; use temporary variable instead
++trailing_comma_in_array # extra comma is not recommended in array initializers
++assign_to_function_call # assignment to a function call
++parseint_missing_radix # parseInt missing radix parameter
+
+
+### Output format
+# Customize the format of the error message.
+# __FILE__ indicates current file path
+# __FILENAME__ indicates current file name
+# __LINE__ indicates current line
+# __ERROR__ indicates error message
+#
+# Visual Studio syntax (default):
++output-format __FILE__(__LINE__): __ERROR__
+# Alternative syntax:
+#+output-format __FILE__:__LINE__: __ERROR__
+
+
+### Context
+# Show the in-line position of the error.
+# Use "+context" to display or "-context" to suppress.
+#
++context
+
+
+### Semicolons
+# By default, assignments of an anonymous function to a variable or
+# property (such as a function prototype) must be followed by a semicolon.
+#
++lambda_assign_requires_semicolon
+
+
+### Control Comments
+# Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
+# the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
+# enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
+# although legacy control comments are enabled by default for backward compatibility.
+#
++legacy_control_comments
+
+
+### JScript Function Extensions
+# JScript allows member functions to be defined like this:
+# function MyObj() { /*constructor*/ }
+# function MyObj.prototype.go() { /*member function*/ }
+#
+# It also allows events to be attached like this:
+# function window::onload() { /*init page*/ }
+#
+# This is a Microsoft-only JavaScript extension. Enable this setting to allow them.
+#
+-jscript_function_extensions
+
+
+### Defining identifiers
+# By default, "option explicit" is enabled on a per-file basis.
+# To enable this for all files, use "+always_use_option_explicit"
+#-always_use_option_explicit
++always_use_option_explicit
+
+# Define certain identifiers of which the lint is not aware.
+# (Use this in conjunction with the "undeclared identifier" warning.)
+#
+# Common uses for webpages might be:
++define window
++define document
++define alert
++define define
++define require
+
+### Files
+# Specify which files to lint
+# Use "+recurse" to enable recursion (disabled by default).
+# To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
+# or "+process Folder\Path\*.htm".
+#
+
++process ./*.js \ No newline at end of file