1 /** 2 * @fileOverview 3 * @author <a href="mailto:ovaraksin@googlemail.com">Oleg Varaksin</a> 4 * @version 0.2 5 */ 6 7 /** 8 * Initialization function for the entire whiteboard application. 9 * @function 10 * @param jsWhiteboard current whiteboard in JSON format 11 * @param whiteboardId whiteboard's id 12 * @param user user (user name) working with this whiteboard 13 * @param usersCount number of users working with this whiteboard 14 * @param pubSubUrl URL for bidirectional communication 15 * @param pubSubTransport transport protocol "long-polling" | "streaming" | "websocket" 16 */ 17 function initWhiteboard(jsWhiteboard, whiteboardId, user, usersCount, pubSubUrl, pubSubTransport) { 18 // bind onclick handler for toolbox items 19 bindOnclickToolboxItems(); 20 21 // configure validator 22 jQuery.validator.addMethod("imageSize", function(value, element, param) { 23 if (jQuery.find(param).length < 1) { 24 return true; 25 } 26 27 return !this.optional(element) && jQuery.validator.methods['digits'].call(this, value, element) && parseInt(value) > 0; 28 }, "Please enter a valid image size (only positive digits are allowed)."); 29 30 var dimensionRules = { 31 required: true, 32 digits: true, 33 min: 1 34 }; 35 36 // create validator 37 dialogValidator = jQuery("#mainForm").validate({ 38 onfocusout: false, 39 onkeyup: false, 40 errorPlacement: function(label, elem) { 41 elem.closest(".validatable").find(".errormsg").append(label); 42 }, 43 wrapper: "li", 44 rules: { 45 inputUrl: { 46 url: true 47 }, 48 imgWidth: { 49 imageSize: "#inputUrl:filled" 50 }, 51 imgHeight: { 52 imageSize: "#inputUrl:filled" 53 }, 54 wbWidth: dimensionRules, 55 wbHeight: dimensionRules 56 }, 57 messages: { 58 inputUrl: "Please enter a valid image URL.", 59 imgWidth: "Please enter a valid image width (only positive digits are allowed).", 60 imgHeight: "Please enter a valid image height (only positive digits are allowed).", 61 wbWidth: "Please enter a valid whiteboard width (only positive digits are allowed).", 62 wbHeight: "Please enter a valid whiteboard height (only positive digits are allowed)." 63 } 64 }); 65 66 // configure dialogs 67 jQuery("#dialogInputText").dialog("option", "buttons", { 68 "Accept": function() { 69 var inputText = jQuery(this).find("#textArea").val(); 70 jQuery(this).dialog("close"); 71 whiteboardDesigner.drawText(inputText); 72 }, 73 "Close": function() { 74 jQuery(this).dialog("close"); 75 } 76 }).bind("dialogclose", function(event, ui) { 77 jQuery(this).find("#textArea").val(''); 78 }); 79 80 jQuery("#dialogInputImage").dialog("option", "buttons", { 81 "Accept": function() { 82 var isValid1 = dialogValidator.element("#inputUrl"); 83 var isValid2 = dialogValidator.element("#imgWidth"); 84 var isValid3 = dialogValidator.element("#imgHeight"); 85 86 if ((typeof isValid1 !== 'undefined' && !isValid1) || (typeof isValid2 !== 'undefined' && !isValid2) || (typeof isValid3 !== 'undefined' && !isValid3)) { 87 // validation failed 88 return false; 89 } 90 91 var jq = jQuery(this); 92 var inputUrl = jq.find("#inputUrl").val(); 93 var imgWidth = jq.find("#imgWidth").val(); 94 var imgHeight = jq.find("#imgHeight").val(); 95 jq.dialog("close"); 96 whiteboardDesigner.drawImage(inputUrl, imgWidth, imgHeight); 97 }, 98 "Close": function() { 99 jQuery(this).dialog("close"); 100 } 101 }).bind("dialogopen", function(event, ui) { 102 // show default width / height 103 jQuery(this).find("#imgWidth").val(whiteboardDesigner.config.properties.image.width); 104 jQuery(this).find("#imgHeight").val(whiteboardDesigner.config.properties.image.height); 105 }).bind("dialogclose", function(event, ui) { 106 // reset input 107 jQuery(this).find("#inputUrl").val(''); 108 // clean up validation messages 109 jQuery("#errorImageUl").html(''); 110 }); 111 112 jQuery("#dialogResize").dialog("option", "buttons", { 113 "Accept": function() { 114 var isValid1 = dialogValidator.element("#wbWidth"); 115 var isValid2 = dialogValidator.element("#wbHeight"); 116 117 if ((typeof isValid1 !== 'undefined' && !isValid1) || (typeof isValid2 !== 'undefined' && !isValid2)) { 118 // validation failed 119 return false; 120 } 121 122 var jq = jQuery(this); 123 var wbWidth = jq.find("#wbWidth").val(); 124 var wbHeight = jq.find("#wbHeight").val(); 125 jq.dialog("close"); 126 whiteboardDesigner.resizeWhiteboard(wbWidth, wbHeight); 127 }, 128 "Close": function() { 129 jQuery(this).dialog("close"); 130 } 131 }).bind("dialogclose", function(event, ui) { 132 //var jq = jQuery(this); 133 //jq.find("#wbWidth").val(''); 134 //jq.find("#wbHeight").val(''); 135 // clean up validation messages 136 jQuery("#errorResizeUl").html(''); 137 }); 138 139 jQuery("#dialogIcons").dialog("option", "buttons", { 140 "Close": function() { 141 jQuery(this).dialog("close"); 142 } 143 }); 144 145 // create a global whiteboard designer instance 146 whiteboardDesigner = new WhiteboardDesigner(new WhiteboardConfig(), whiteboardId, user, pubSubUrl, pubSubTransport); 147 148 // restore existing whiteboard if any exists 149 if (!isBlankObject(jsWhiteboard)) { 150 whiteboardDesigner.restoreWhiteboard(jsWhiteboard); 151 } 152 153 // subscribe to bidirectional channel 154 whiteboardDesigner.subscribePubSub(); 155 156 if (usersCount > 1) { 157 // notificate subscribers about new user 158 setTimeout(function() { 159 whiteboardDesigner.joinUser(usersCount); 160 }, 1000); 161 } 162 } 163 164 /** 165 * Checks whether an JavaScript object is null or empty. 166 * @function 167 * @param obj any JavaScript object 168 */ 169 function isBlankObject(obj) { 170 if (obj == null) { 171 return true; 172 } 173 174 for (var prop in obj) { 175 if (obj.hasOwnProperty(prop)) { 176 return false; 177 } 178 } 179 180 return true; 181 } 182 183 /** 184 * Sets auto width of the given dialog on dialog's show event. 185 * @function 186 * @param jqDialog jQuery object for dialog 187 */ 188 function onShowAutoWidthDialog(jqDialog) { 189 // fix for auto width in IE 190 var parent = jqDialog.parent(); 191 var contentWidth = jqDialog.width(); 192 parent.find('.ui-dialog-titlebar').each(function() { 193 jQuery(this).width(contentWidth); 194 195 }); 196 parent.removeClass("autoWidthDialog").width(contentWidth + 26); 197 jqDialog.dialog('option', 'position', 'center'); 198 199 // fix for scrollbars in IE 200 jQuery('body').css('overflow', 'hidden'); 201 jQuery('.ui-widget-overlay').css('width', '100%'); 202 } 203 204 /** 205 * Sets auto width of the given dialog on dialog's hide event. 206 * @function 207 * @param jqDialog jQuery object for dialog 208 */ 209 function onHideAutoWidthDialog(jqDialog) { 210 // fix for auto width in IE 211 var parent = jqDialog.parent(); 212 parent.find('.ui-dialog-titlebar').each(function() { 213 // reset titlebar width 214 jQuery(this).css('width', ''); 215 }); 216 parent.addClass("autoWidthDialog"); 217 218 // fix for scrollbars in IE 219 jQuery('body').css('overflow', 'auto'); 220 } 221 222 /** 223 * Adjusts width of the given dialog on dialog's show event. 224 * @function 225 * @param jqDialog jQuery object for dialog 226 */ 227 function adjustOpenAutoWidthDialog(dialogId) { 228 var jqDialog = jQuery('#' + dialogId); 229 var parent = jqDialog.parent(); 230 parent.find('.ui-dialog-titlebar').each(function() { 231 jQuery(this).css('width', ''); 232 }); 233 parent.addClass('autoWidthDialog'); 234 235 onShowAutoWidthDialog(jqDialog); 236 } 237 238 /** 239 * Removes unused panels after "pin panels". 240 * @function 241 */ 242 function removeUnusedDialogs() { 243 jQuery('#toolboxDialog').remove(); 244 jQuery('#propertiesDialog').remove(); 245 jQuery('#monitoringDialog').remove(); 246 } 247 248 /** 249 * Binds onlick event handlers to all items in the "Toolbox" panel. 250 * @function 251 */ 252 function bindOnclickToolboxItems() { 253 var toolboxItems = jQuery('.toolboxItem'); 254 toolboxItems.bind('click', function() { 255 toolboxItems.removeClass('ui-state-selected'); 256 jQuery(this).addClass('ui-state-selected'); 257 }); 258 } 259 260 /** 261 * Pins panels. 262 * @function 263 */ 264 function pinPanels() { 265 removeUnusedDialogs(); 266 bindOnclickToolboxItems(); 267 whiteboardDesigner.setIdSubviewProperties('#pinnedSubview'); 268 269 // show properties of last selected element 270 if (whiteboardDesigner.getSelectedObject() != null) { 271 whiteboardDesigner.showSelectedProperties(whiteboardDesigner.getSelectedObject()); 272 } 273 274 // hide loading dialog 275 loadingDialogWidget.hide(); 276 } 277 278 /** 279 * Unpins panels. 280 * @function 281 */ 282 function unpinPanels() { 283 bindOnclickToolboxItems(); 284 whiteboardDesigner.setIdSubviewProperties('#unpinnedSubview'); 285 286 // show properties of last selected element 287 if (whiteboardDesigner.getSelectedObject() != null) { 288 whiteboardDesigner.showSelectedProperties(whiteboardDesigner.getSelectedObject()); 289 } 290 291 // hide loading dialog 292 loadingDialogWidget.hide(); 293 } 294 295 /** 296 * Converts RGB color to Hex color. This is an utility function for Color Picker. 297 * @function 298 * @param color color as RGB 299 */ 300 function colorToHex(color) { 301 if (color.substr(0, 1) === '#') { 302 return color; 303 } 304 var digits = /(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(color); 305 306 var red = parseInt(digits[2]); 307 var green = parseInt(digits[3]); 308 var blue = parseInt(digits[4]); 309 310 var rgb = blue | (green << 8) | (red << 16); 311 return digits[1] + '#' + rgb.toString(16); 312 } 313 314 /** 315 * Sends changed properties to {@link WhiteboardDesigner} which sends them to the server. 316 * @function 317 * @param type element type 318 * @param resize boolean flag, true - resize element, false - otherwise. 319 * @param resize boolean flag, true - rotate element, false - otherwise. 320 */ 321 function sendPropertiesChanges(type, resize, rotate) { 322 whiteboardDesigner.sendPropertiesChanges(type, resize, rotate); 323 } 324 325 /** 326 * Toggles logging component. 327 * @function 328 */ 329 function toggleLogging() { 330 log.toggle(); 331 whiteboardDesigner.logging = !whiteboardDesigner.logging; 332 } 333