From d2491b978ff73a549bda131841a4f58bc28bc43f Mon Sep 17 00:00:00 2001 From: Xuqing Kuang Date: Thu, 13 Sep 2012 14:31:23 +0800 Subject: [PATCH] [Event handler] Refined the whole code to be a standalone View. Refined the the event handler to be a standalone View, and added a icon to indicate existence of event handlers in outline View. --- index.html | 1 + src/css/builder.css | 61 +++-- src/css/images/eventHandlerIcon.png | Bin 0 -> 834 bytes src/js/main.js | 10 + src/js/views/eventHandler.js | 367 ++++++++++++++++++++++++++++ src/js/views/outline.js | 17 +- src/js/views/property.js | 320 +----------------------- 7 files changed, 436 insertions(+), 340 deletions(-) create mode 100644 src/css/images/eventHandlerIcon.png create mode 100644 src/js/views/eventHandler.js 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 0000000000000000000000000000000000000000..ea36a69f7c5502ca3a94e5d3e4780972e60f3411 GIT binary patch literal 834 zcmV-I1HJr-P)=^WFR1J9qw@pC)7DRE1O<{6Q?D8#ggZ zRZ!4{;zEirp%fP*xDXdX#f3!7q9t`k5sL)6Xck&c#6blSaZzpB(m<;clhCxZHciYp zlbN~q`&=XwQ}k@ld4D)BuUKo@K5v#L2DFkwqhW@gf8u<8?;U>vY5{Cz;3H?Ia*sx6-%W;3qWmwRbmJzgZV#JRK2!-sB=#^Jv?02TLimFjDZXSv_ea7=PGyiFK@1e zQ>W{E{>3u+TWZ|iS0fCg!Q4IieE>&t{R2wzv4{vjs~Pd=!*lfYQ~|+SI6YJ6@xg#+ zp7i+fl+SuIj_>Pz-_M*m;c6uXWWz}-gk1Mu+&|D(2N8H`e+GcJ-)nH;S3~cv2xF{r ztP~X3p?`mBcwp~U&dzFnn^QNXbEI^gFTbji44Ujn*NLJK6WJkUk$n5ebqwGB)Xj;h zE;>8f@d{_oR+(R@^ZKiC-Y7Q6Cf8{;Lad4M?sgSpgq0PK=N?;QN5%jGSnk{tF#1js zfWseJemMs{xe#LwO0WxUf-n^NZ>zHJ-nC7z01%5Qz;dL#%2cI=r|qUUSx_Jq0BgZ@ zLiRthgyR@~pR=5tuF-5+KsYvWgX5ER5=kHJ`?y*o%B`rDv1Mzmi464htg(36WAuY= zUVBS3dr|PTF!gnnk3L-|+mR)e$q-MZ@I2orP1*VGA(wy%U2>s4~GQtG#y=CWIMY^rqk$HFg`N;(lHlcp1+HE8^6n1cQ77!V3YLaB9v2O z{F6BGbc#eGMlzixk;uvFaD=Yx7uJVGSR`XWmLZR2G^Hc%r9D8$D;ihK@b=( z2#zi}&0?vrQ6~AnItx+3m~g03YvfHBVigP8)fLb6%OkHGxT((n0AIT~Hj^MY`~Uy| M07*qoM6N<$g2e)S=l}o! literal 0 HcmV?d00001 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 = $('