This tutorial studies the design and implementation of "My Notes" application
// GLOBAL settings are stored per each application
// Get global application setting for key $key. If no setting with $key is found, $default will be returned
function get_global_setting($key, $default = null);
// Set global application setting for key $key with value $value. Arrays and Objects that can be serialized are welcome
function set_global_setting($key, $value);
// Set function saves the modified global settings
function save_global_settings();
// PRIVATE settings are stored for each "view", which can be "profile" or "user_home" (shared settings) or userpage, etc
// Get private application setting for key $key. If no setting with $key is found, $default will be returned
function get_private_setting($key, $default = null);
// Set global application setting for key $key with value $value. Arrays and Objects that can be serialized are welcome
function set_private_setting($key, $value);
// Set function saves the modified global settings
function save_private_settings();
<?php
/*
* Application: My Notes
* Author: SocialEngineMods
*
*
*/
class app_mynotes extends semods_myapp {
/***** VIEW SWITCHER *****/
/*
* $view can be "user_home", "profile", "userpage", "group", etc
* $view_id is the view identifier, for example page_id for "userpage", event_id for "event", etc
* $params are additinal passed parameters
*
* The function should return "true" if there is any content or "false" if no content is available
*
*/
function handleview( $view, $view_id, &$params ) {
switch($view) {
case "userpage":
case "user_home":
return $this->any_view( $view, $view_id, &$params );
default:
return false;
}
}
/***** USER HOME VIEW *****/
/*
* This function handles user_home view and also any other view
*/
function any_view( $view, $view_id, &$params ) {
global $task;
$max_size = $this->app->get_global_setting('max_size', 2048);
$save_period = $this->app->get_global_setting('save_period', 60); // 1 minute
// Loads default text 'Type any text here and it will be auto saved.'
$welcome_text_default = semods::get_language_text( 101001014 );
$welcome_note = $this->app->get_global_setting('welcome_note', $welcome_text_default);
// some background colors
$color = $this->app->get_private_setting('color', 'white');
$color_codes = array('red' => array('title' => 101001002,
'code' => '#FFE0E1'
),
'orange' => array('title' => 101001003,
'code' => '#FEE8BD'
),
'yellow' => array('title' => 101001004,
'code' => '#FFFFE0'
),
'green' => array('title' => 101001005,
'code' => '#EEFFE0'
),
'blue' => array('title' => 101001006,
'code' => '#EFF5FF'
),
'white' => array('title' => 101001007,
'code' => '#FFFFFF'
)
);
// AJAX EDIT SETTINGS - LOAD
// This task is called when user selects "edit" menu option from the box properties menu
if($task == "editcontent") {
// preload languages. sigh.
foreach($color_codes as $color_code) {
SE_Language::_preload($color_code['title']);
}
$params['ajax_response'] = true;
$params['color'] = $color;
$params['color_codes'] = $color_codes;
$params['template'] = 'mynotes_edit';
return true;
}
// AJAX EDIT SETTINGS - SAVE
// This task is called when user clicks "save" on the form loaded with "editcontent" task
if($task == "doajaxsave") {
$color = semods::getpost('color');
$this->app->set_private_setting('color', $color);
$this->app->save_private_settings();
// save stuff and fallback, make it ajax
$params['ajax_response'] = true;
}
// AJAX SAVE text task
// This task is called using javascript side
if($task == "dosave") {
$text = semods::getpost('text','');
// make sure the text size is allowed
// TODO: notify user if the text is too large and is being cut.
if(strlen($text) > $max_size) {
$text = substr($text,0,$max_size);
}
$this->app->set_private_setting('text', $text);
$this->app->save_private_settings();
// this is ajax request/response
$params['ajax_response'] = true;
// by default 'status' is '0', i.e. everything is ok. we can overide it here
// $params['response'] = array( 'status' => 1 );
// if there is a `template` parameter it will be inserted into response['html']
return true;
}
/* LOAD STUFF */
$text = $this->app->get_private_setting('text',$welcome_note);
$color_code_item = semods::g($color_codes, $color, $color_codes['white']);
// optional - do not show link to app in directory, in the box title
//$params['ui_noheaderlink'] = true;
$params['text'] = $text;
$params['max_size'] = $max_size;
$params['save_period'] = $save_period;
$params['color_code'] = $color_code_item['code'];
$params['template'] = 'mynotes';
return true;
}
}
?>
/* This function will make an ajax request with parameters, automatically appending * application id and placement */ function request (params, onDone, onFail); /* This function will create a timer and periodically call the 'on_timer' function, if defined */ function start_timer(timer_period); /* Directly stop the timer */ function start_timer(timer_period); /* Define the timer period, in seconds */ function set_timer_period_in_seconds(timer_period); /* This will ask the API to call us when the 'box' is dropped after being dragged from another location * The function 'on_drop' will be called with first parameter being identity and placement of the box * */ function register_on_drop(); /* This will ask the API to call us when the 'box' content is loaded using ajax * The function 'on_ajax_load' will be called * */ functon register_on_ajax_load(); /* This function will submit a form using ajax, posting all the form fields (input, textarea, select) * */ functon submit_form (form_id); /* This function will load content using ajax * */ funcion load_content();
<!--
THIS DEFINES OUR STYLES
In the future API version it will be possible to separate the styles from the template
-->
{literal}
<style>
/* disable padding for content box */
#appcontent_app_{/literal}{$appdata.app_id}{literal} {
padding: 0px;
}
DIV.app_mynotes_content {
padding: 2px;
text-align: center;
}
#app_mynotes_text {
overflow-x:auto;
}
.app_mynotes_progress {
height:18px;
padding-left: 2px;
padding-bottom: 2px;
position: absolute;
top: 6px;
right: 8px;
}
.app_mynotes_text_readonly {
text-align: left;
padding: 5px;
}
</style>
{/literal}
<!--
THIS IS OUR JAVASCRIPT APP PART `se_app_mynotes` inherits from `semods_app`
-->
{literal}
<script type='text/javascript'>
var se_app_mynotes = semods_app.extend({
max_size : 0,
constructor : function( app_id, page_id, view_id, instance_id ) {
this._super( app_id, page_id, view_id, instance_id );
this.register_on_drop();
this.register_on_ajax_load();
},
// save the current text
save_text : function() {
var text = $('app_mynotes_text').value;
if(text != '') {
// show "saving..." indicator
$('app_mynotes_progress').setStyle('display','block');
// ajax request to save content
this.request( 'task=dosave&text='+text, this.on_text_saved.bind(this),this.on_save_failed.bind(this) );
}
},
// automatically adjust the textarea width to the content box size
auto_size : function() {
if($('app_mynotes_text')) {
$('app_mynotes_text').style.width = $('app_mynotes_content').offsetWidth - 10 + 'px';
}
},
// auto resize the text box after dropping the box onto another column
on_drop : function(identity) {
this.auto_size();
},
// auto resize the text box after content is loaded via ajax
on_ajax_load : function(identity,editing) {
if(!editing) {
this.auto_size();
textarea_autogrow("app_mynotes_text")
}
},
// periodic timer function
on_timer : function() {
this.save_text();
this.start_timer();
},
// when text box looses focus, save the text and stop the timer
save_and_finish : function() {
this.stop_timer();
this.save_text();
},
// ajax request success function
on_text_saved : function( ajax_obj, response_text ) {
$('app_mynotes_progress').setStyle('display','none');
},
// ajax request failure
on_save_failed : function( response ) {
$('app_mynotes_progress').setStyle('display','none');
// this API function will show notification about error. The first parameter can be custom error message text.
apps_show_error_message();
}
});
// after browser loads, autosize the text area and autogrow it
SEMods.Browser.register_onload( function() { app_mynotes.auto_size(); textarea_autogrow("app_mynotes_text"); } );
</script>
{/literal}
<-- required only if owner is viewing the content -->
{if $appdata.is_owner}
<script type='text/javascript'>
var app_mynotes = new se_app_mynotes( '{$appdata.app_id}', '{$appdata.page_id}', '{$appdata.view_id}', '{$appdata.instance_id}' );
app_mynotes.max_size = '{$appdata.max_size}';
app_mynotes.set_timer_period_in_seconds('{$appdata.save_period}');
</script>
{/if}
<div style="position:relative">
<div class="app_mynotes_content" id="app_mynotes_content" name="app_mynotes_content">
{if $appdata.is_owner}
<textarea onfocus="app_mynotes.start_timer()" onblur="app_mynotes.save_and_finish()" id="app_mynotes_text"
name="app_mynotes_text" style="background-color: {$appdata.color_code}">{$appdata.text}</textarea>
{else}
<div class="app_mynotes_text_readonly" style="background-color: {$appdata.color_code};">{$appdata.text|nl2br}</div>
{/if}
</div>
<div class="app_mynotes_progress" id="app_mynotes_progress" name="app_mynotes_progress" style="display:none;">
<img src="{$appdata.app_dir}/images/ajaxprogress.gif"> {lang_print id=101000010}
</div>
</div>
<?xml version="1.0" encoding="UTF-8"?>
<application>
<version>1.00</version>
<title>My Notes</title>
<author>SocialEngineMods</author>
<author>
<name>SocialEngineMods</name>
<email>info@socialenginemods.net</email>
<website>http://www.socialenginemods.net/</website>
</author>
<hash>23cd54a4d76be7274fe1b76d60ef9582</hash>
<type>app</type>
<description><![CDATA[My notes on page]]></description>
<pic></pic>
<icon>icon_note.png</icon>
<settings><![CDATA[]]></settings>
<requires_install>0</requires_install>
<show_in_directory>1</show_in_directory>
<requires_add>0</requires_add>
<tags><![CDATA[notes]]></tags>
<user_menu_file></user_menu_file>
<user_menu_title>101001000</user_menu_title>
<global_profile_menu>0</global_profile_menu>
<layout_options>15</layout_options>
<pages_canvas></pages_canvas>
<pages_admin>101000012</pages_admin>
<inplace_edit>1</inplace_edit>
<show_in_user_menu>0</show_in_user_menu>
<after_add>user_home</after_add>
<pages list="true">
<page name="user_home">
<default_stripe>w</default_stripe>
<default_container>root</default_container>
<stripecontentvaries>0</stripecontentvaries>
</page>
<page name="userpage">
<default_stripe>w</default_stripe>
<default_container>tabs</default_container>
<stripecontentvaries>0</stripecontentvaries>
</page>
</pages>
<install>
<sql><![CDATA[
]]></sql>
<sqlignore><![CDATA[
]]></sqlignore>
</install>
<unnstall>
<sql><![CDATA[
]]></sql>
<sqlignore><![CDATA[
]]></sqlignore>
</unnstall>
<languages list="true">
<language code="en" name="English" list="true">
<languagevar id="101001000"><![CDATA[My Notes]]></languagevar>
<languagevar id="101001001"><![CDATA[Background Color:]]></languagevar>
<languagevar id="101001002"><![CDATA[Red]]></languagevar>
<languagevar id="101001003"><![CDATA[Orange]]></languagevar>
<languagevar id="101001004"><![CDATA[Yellow]]></languagevar>
<languagevar id="101001005"><![CDATA[Green]]></languagevar>
<languagevar id="101001006"><![CDATA[Blue]]></languagevar>
<languagevar id="101001007"><![CDATA[White]]></languagevar>
<languagevar id="101001008"><![CDATA[Application Settings]]></languagevar>
<languagevar id="101001009"><![CDATA[Global Settings]]></languagevar>
<languagevar id="101001010"><![CDATA[Maximum note size]]></languagevar>
<languagevar id="101001011"><![CDATA[characters]]></languagevar>
<languagevar id="101001012"><![CDATA[Autosave period - while the text area is focused and the user is typing.]]></languagevar>
<languagevar id="101001013"><![CDATA[seconds]]></languagevar>
<languagevar id="101001014"><![CDATA[Type any text here and it will be auto saved]]></languagevar>
</language>
</languages>
</application>