diff --git a/index.html b/index.html index be1f29a0..21f3e958 100644 --- a/index.html +++ b/index.html @@ -47,6 +47,7 @@ + diff --git a/src/css/builder.css b/src/css/builder.css index 335c39af..eb1dac77 100644 --- a/src/css/builder.css +++ b/src/css/builder.css @@ -1563,17 +1563,19 @@ input.screenCoordinate::-webkit-inner-spin-button { margin: 0 0.6em; } -#eventHandlerDialog { +.eventHandler { + width: 980px !important; /* Override computed style */ + height: 560px !important; /* Override computed style */ overflow: hidden; } -#eventHandlerDialog .title { +.eventHandler .title { position: relative; height: 52px; background-color: #E4E5DF; } -#eventHandlerDialog .title > label { +.eventHandler .title > label { position: absolute; left: 10px; top: 16px; @@ -1583,32 +1585,31 @@ input.screenCoordinate::-webkit-inner-spin-button { font-weight: 600; /* semi-bold */ } - -#eventHandlerDialog .wrap_left { +.eventHandler .wrap_left { position: relative; width: 230px; border-right: 1px solid #dededc; } -#eventHandlerDialog .wrap_left .container { +.eventHandler .wrap_left .container { position: absolute; width: 100%; margin: 10px; } -#eventHandlerDialog .wrap_left .container * { +.eventHandler .wrap_left .container * { display: inline-block; } -#eventHandlerDialog .wrap_left .container select { +.eventHandler .wrap_left .container select { position: absolute; top: 10px; left: 0px; width: 270px; } -#eventHandlerDialog .wrap_left .container fieldset { +.eventHandler .wrap_left .container fieldset { position: absolute; top: 40px; width: 244px; @@ -1616,11 +1617,11 @@ input.screenCoordinate::-webkit-inner-spin-button { overflow: auto; } -#eventHandlerDialog .wrap_left .container fieldset ul { +.eventHandler .wrap_left .container fieldset ul { margin: 0px; } -#eventHandlerDialog .wrap_left .container fieldset li { +.eventHandler .wrap_left .container fieldset li { display: block; padding: 8px 8px 8px 8px; margin-left: -36px; @@ -1630,36 +1631,40 @@ input.screenCoordinate::-webkit-inner-spin-button { border-bottom: 1px solid #CCC; } -#eventHandlerDialog .wrap_left .container fieldset li.ui-selected { +.eventHandler .wrap_left .container fieldset li.ui-selected { background-color: #4AE57B; } -#eventHandlerDialog .wrap_left .container fieldset li > a.link { +.eventHandler .wrap_left .container fieldset li > a.link { padding-top: 8px; width: 160px; height: 34px; } -#eventHandlerDialog .wrap_left .container button.doneButton { +.eventHandler .wrap_left .container fieldset a.ui-button { + margin-top: 0px; + float: right; +} + +.eventHandler .wrap_left .container button.doneButton { position: absolute; top: 440px; left: 46px; width: 180px; } -#eventHandlerDialog .wrap_right { +.eventHandler .wrap_right { width: 630px; } -#eventHandlerDialog .wrap_right .container { +.eventHandler .wrap_right .container { overflow: auto; resize: none; - height: 600px; width: 98%; margin: 6px; } -#eventHandlerDialog .wrap_right .container .CodeMirror { +.eventHandler .wrap_right .container .CodeMirror { margin: 4px; -webkit-border-radius: 4px; -moz-border-radius: 4px; @@ -1669,6 +1674,24 @@ input.screenCoordinate::-webkit-inner-spin-button { height: 470px; } -#eventHandlerDialog .wrap_right .container .CodeMirror .CodeMirror-scroll { +.eventHandler .wrap_right .container .CodeMirror .CodeMirror-scroll { height: 464px; } + +.eventHandlerIcon { + display: inline-block; + position: relative; + top: 4px; + left: 4px; + margin-right: 1px; + text-indent: -3000px; + height: 20px; + width: 20px; + background-repeat: no-repeat; + background-position: left top; + background-image: url('images/eventHandlerIcon.png'); +} + +.eventHandlerIcon:hover { + opacity: 0.8; +} diff --git a/src/css/images/eventHandlerIcon.png b/src/css/images/eventHandlerIcon.png new file mode 100644 index 00000000..ea36a69f Binary files /dev/null and b/src/css/images/eventHandlerIcon.png differ diff --git a/src/js/main.js b/src/js/main.js index 98900651..7ca2cba1 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -315,6 +315,10 @@ .addClass('view live flex1'); this.ui.liveView.append('
'); + this.ui.eventHandlerView = $('
').appendTo(container) + .attr('id', 'eventHandlerView') + .addClass('view eventHandler'); + $('.pageView').each( function () { $(this).pageView(); $(this).pageView('option', 'model', ADM); @@ -330,6 +334,11 @@ $(this).propertyView('option', 'model', ADM); }); + $('.eventHandler').each( function() { + $(this).eventHandlerView(); + $(this).eventHandlerView('option', 'model', ADM); + }) + $('.paletteView').each( function () { $(this).paletteView(); widget._bindResizeEvent(this, 'paletteView'); @@ -431,6 +440,7 @@ this.ui.layoutView = $('.view.layout').eq(0); this.ui.codeView = $('.view.code').eq(0); this.ui.liveView = $('.view.live').eq(0); + this.ui.eventHandlerView = $('.view.eventHandler').eq(0); this.ui.tools = $('.tools-primary').eq(0); this.ui.extras = $('.tools-secondary').eq(0); }, diff --git a/src/js/views/eventHandler.js b/src/js/views/eventHandler.js new file mode 100644 index 00000000..a93dc569 --- /dev/null +++ b/src/js/views/eventHandler.js @@ -0,0 +1,367 @@ +/* + * Rapid Interface Builder (RIB) - A simple WYSIWYG HTML5 app creator + * Copyright (c) 2011-2012, Intel Corporation. + * + * This program is licensed under the terms and conditions of the + * Apache License, version 2.0. The full text of the Apache License is at + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +"use strict"; +// Event Handler view widget + +(function($, undefined) { + $.widget('rib.eventHandlerView', $.rib.baseView, { + _create: function() { + var formContainer, leftPanel, leftPanelContainer, + rightPanel, eventElement, eventSelectElement, + eventEditorContainer, eventEditor, formElement, + jsCode, eventHandlersList, + o = this.options, e = this.element, self = this, + uniqueIdName = 'id'; + + // Chain up to base class _create() + $.rib.baseView.prototype._create.call(this); + + /* + * Construct the page layout + */ + // Page layout initial + formContainer = $('
'); + leftPanel = $('
') + .appendTo(formContainer) + rightPanel =$('
') + .appendTo(formContainer) + + /*** Left panel contents ***/ + + $('
') + .appendTo(leftPanel); + + leftPanelContainer = $('
') + .addClass('container propertyItems') + .appendTo(leftPanel); + + // Construct event options elements + eventSelectElement = $('' + ).appendTo(leftPanelContainer); + + // Initial the event handlers list + eventHandlersList = $('
') + .append($('Event handlers')) + .appendTo(leftPanelContainer); + + // Create the DONE button + $('') + .addClass('buttonStyle doneButton') + .click( function (e) { + self.element.dialog('close'); + }) + .button() + .appendTo(leftPanelContainer); + + /*** Right panel contents ***/ + + $('
') + .appendTo(rightPanel); + + // Construct code editor element + eventEditorContainer = $('
') + .addClass('container') + .appendTo(rightPanel); + eventEditor = CodeMirror( + eventEditorContainer[0], + { + mode: "javascript", + readOnly: 'nocursor', + } + ); + eventEditorContainer.show(); + + /*** Dialog contents ***/ + formElement = $('
') + .append(formContainer) + .bind('submit', function(e) { + e.preventDefault(); + var node = ADM.getSelectedNode(), + formData = $(this).serializeJSON(); + + formData['jsCode'] = eventEditor.getValue(); + + // If ID is blank, generate a unique one. + if(node.getProperty(uniqueIdName) == '') { + node.generateUniqueProperty( + uniqueIdName, true + ); + } + + // Save editor content to ADM property. + if (formData.currentEvent) { + node.setProperty( + formData.currentEvent, + formData.jsCode + ); + // Refresh event handlers list. + self.refresh(e, self); + } + + // Load the jsCode + // + // Checking the event select element changed + // + // If old event is not equal to current event in + // select, it's meaning the select changed not + // the window close, so we need to load the JS + // code from new selected property and change the + // editor content. + if (formData.currentEvent != formData.selectedEvent) { + if (formData.selectedEvent) { + // Load the event property content and set + // the editor content. + jsCode = node.getProperty( + formData.selectedEvent + ); + if (typeof(jsCode) != 'string') + jsCode = ''; + eventEditor.setOption('readOnly', false); + eventEditor.setValue(jsCode); + } else { + // Check the selection of event, if + // selected blank will clean up the editor + // content and set editor to be read only. + eventEditor.setValue(''); + eventEditor.setOption( + 'readOnly', 'nocursor' + ); + } + + // Set currentEvent element to selctedEvent. + eventElement.val(formData.selectedEvent); + }; + }); + + this.formElement = formElement; + this.eventElement = eventElement; + this.eventSelectElement = eventSelectElement; + this.eventHandlersList = eventHandlersList; + this.eventEditor = eventEditor; + this.element.append(formElement); + this.element.dialog({ + modal: true, + width: 980, + height: 560, + resizable: false, + autoOpen: false + }) + .bind('dialogopen', function(e) { + if (eventSelectElement.val() == '') + self._initialEditorContent(self); + }) + .bind('dialogclose', function(e) { + self.formElement.trigger('submit'); + }); + + return this; + }, + + _setOption: function(key, value) { + // Chain up to base class _setOptions() + // FIXME: In jquery UI 1.9 and above, instead use + // this._super('_setOption', key, value) + $.rib.baseView.prototype._setOption.apply(this, arguments); + + switch (key) { + case 'model': + this.refresh(null, this); + break; + default: + break; + } + }, + + refresh: function(event, widget) { + widget = widget || this; + var matchedProps, + eventElement = widget.element.find('input[name="currentEvent"]'), + eventSelectElement = widget.element.find('select'), + eventHandlersList = widget.element.find('fieldset'), + node = ADM.getSelectedNode(), id = node.getProperty('id'); + + // Restore the select element to be blank + if (event && event.name == 'selectionChanged') + widget._initialEditorContent(widget); + + // Update dialog title. + widget.element.dialog({ + title: "Event Handlers - " + + BWidget.getDisplayLabel(node.getType()) + + (id ? ' (' + id + ')' : '' ), + }) + + // Regenerate event select options/list. + matchedProps = node.getMatchingProperties({'type': 'event'}); + widget._generateEventSelectElement( + widget, eventSelectElement, node, matchedProps + ); + widget._generateEventHandlersList( + widget, eventSelectElement, node, matchedProps + ).replaceAll(eventHandlersList); + }, + + // Private functions + _createPrimaryTools: function() { + return $(null); + }, + + _createSecondaryTools: function() { + return $(null); + }, + + _selectionChangedHandler: function(event, widget) { + widget = widget || this; + widget.refresh(event, widget); + }, + + _initialEditorContent: function(widget) { + widget = widget || this; + widget.eventSelectElement.val(''); + widget.eventElement.val(''); + // Clean up the editor contents and restore it to be read only. + widget.eventEditor.setValue(''); + widget.eventEditor.setOption('readOnly', 'nocursor'); + }, + + /* + * Elements construction functions. + */ + + // Generate the event property select options. + _generateEventSelectElement: function(widget, eventSelectElement, node, matchedProps) { + var selected, newSelectElement, result, + optionElement, eventName, optionsGroup; + + // If eventSelectElement is not exist then create one, otherwise + // restore it to initial. + if (eventSelectElement.length == 0) { + eventSelectElement = $(''); + } else { + selected = eventSelectElement.val(); + eventSelectElement.empty(); + } + + // Added a initial blank option; + $('') + .addClass('cm-inactive') + .appendTo(eventSelectElement); + + // TODO: Classify the events and use optgroup to + // genereate it. + /* + optionsGroup = $( + '' + ) + .appendTo(eventSelectElement); + */ + + // Generate event select options. + for (eventName in matchedProps) { + optionElement = $('